• 1 ,j , "¡' j I I ¡' ,1" r , ¡' I I I l ' •j " I I
APROVECHE AL MÁXIMO SU POTENCIAL ILIMITADO
SILVERUGHT PARA DISEÑADORES
Y DESARROLLADORES
MICROSOFT EXPRESSION BLEND 2
Y MICROSOFT VISUAL STUDIO 2008
UNQ, WCFy SERVICIOS WEB CON C#
CREACiÓN DE ANIMACIONES Y TÉCNICAS
DE ESCRITURA PARA DISPOSITIVOS TÁCTILES
INTERACCiÓN CON JAVASCRIPT, HTML, XML y CSS
DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO
DE APLICACIONES PARA INTERNET
INCLUYE
NOVEDADES DE
LA VERSiÓN 3.0
por MATÍAS IACONO
En este sitio encontrará una gran variedad de recursos y software relacionado,
que le servirán como complemento al contenido del libro. Además, tendrá la po-
sibilidad de estar en contacto con los editores, y de participar del foro de lecto-
res, en donde podrá intercambiar opiniones y experiencias.
Silverlight is the cross-platform, cross-browser plug-in
for rich interactive applications and cutting-edge
media experiences. With advanced tips from our
expert, this book provides practical, grounded advice,
and rich examples, to be ready for today´s challenges.
SILVERLIGHT
DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO
DE APLICACIONES PARA INTERNETCONTENIDO
N I V E L D E U S U A R I O
PRINCIPIANTE INTERMEDIO AVANZADO EXPERTO
1 | INTRODUCCIÓN A SILVERLIGHT
Experiencia de usuario y portabilidad | Arquitectura de
Silverlight 2 | Microsoft .NET Framework | Interfaz de usuario
y presentación | El código XAML | Herramientas de desarrollo
2 | MICROSOFT EXPRESSION BLEND 2
Silverlight con Expression Blend | Explorador de soluciones |
Entorno | Barra de herramientas | Crear nuestra primera
aplicación
3 | SILVERLIGHT PARA DESARROLLADORES
Puesta a punto de Visual Studio 2008 | Crear la primera
aplicación | Interoperabilidad con Expression Blend 2
4 | XAML AL EXTREMO
El lenguaje XAML | Declaración de objetos | Controles y
componentes | Grid | GridSplitter | Canvas | StackPanel |
ScrollViewer | Border | Controles de iteración con el usuario |
Button | CheckBox | RadioButton | HyperlinkButton | Image |
ComboBox | ListBox | TextBlock | TextBox | PasswordBox |
DataGrid | Calendar | DatePicker | ProgressBar | Slider
5 | LUZ, CÁMARA, ACCIÓN
Mover objetos | Transformaciones de traslación, rotación,
escalar y distorsión | Animaciones | DoubleAnimation |
ColorAnimation | Estilos y plantillas
6 | CERRAR EL CÍRCULO
MediaElement | Ejecutar sonidos | Elementos con video
embebido | Deep Zoom | Dibujar con InkPresenter | Áreas
de dibujo
7 | INTERCONEXIÓN
Ampliar las funcionalidades | Silverlight desde C# |
WebClient | Enviar información | Capacidad de
almacenamiento | OpenFileDialog | Manejo de hilos |
Temporizador | Hilos y eventos | Consumir servicios desde
Silverlight | Manipular datos | LinQ
8 | EL NAVEGADOR Y SU DOMINIO
Conectar tecnologías | Silverlight 2 y HTML | HtmlDocument
y HtmlElement | HtmlPage | HtmlWindow | Cookies |
Modificar CSS | Silverlight 2 y JavaScript | Llamar funciones
| Objetos para JavaScript
APÉNDICE A | SILVERLIGHT FUERA DE WINDOWS
APÉNDICE B | SILVERLIGHT 3, LA NUEVA GENERACIÓN
redusers.com
SILVERLIGHT
tapa Silverlight.qxp 21/09/2009 11:07 a.m. PÆgina 1
CONÉCTESE CON LOS MEJORES
LIBROS DE COMPUTACIÓN
DESCUBRA EL POTENCIAL DE WINDOWS VISTA
MANUALES USERS I 384 páginas I ISBN 978-987-1347-40-7
MANEJE LAS HERRAMIENTAS DE VISTA COMO UN EXPERTO
MANUALES USERS I 352 páginas I ISBN 978-987-663-007-8
DESARROLLE APLICACIONES PARA WINDOWS Y LA WEB
MANUALES .CODE I 368 páginas I ISBN 978-987-1347-32-2
usershop.redusers.com
APRENDA A PROGRAMAR CON EL LENGUAJE MÁS POTENTE
DESARROLLADORES I 400 páginas I ISBN 978-987-1347-76-6
RT_Bombo_LIBROSilverlight.qxp 21/09/2009 17:07 Página RT2
DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO
DE APLICACIONES PARA INTERNET
00_Silverlight.qxp 9/30/09 1:16 PM Page 1
TÍTULO: SILVERLIGHT
AUTOR: Matías Iacono
COLECCIÓN: Manuales USERS
FORMATO: 17 x 24 cm
PÁGINAS: 352
Copyright © MMIX. Es una publicación de Gradi S.A. Hecho el depósito que marca la
ley 11723. Todos los derechos reservados. No se permite la reproducción parcial o to-
tal, el almacenamiento, el alquiler, la transmisión o la transformación de este libro, en
cualquier forma o por cualquier medio, sea electrónico o mecánico, mediante foto-
copias, digitalización u otros métodos, sin el permiso previo y escrito del editor. Su
infracción está penada por las leyes 11723 y 25446. La editorial no asume responsa-
bilidad alguna por cualquier consecuencia derivada de la fabricación, funcionamien-
to y/o utilización de los servicios y productos que se describen y/o analizan. Todas las
marcas mencionadas en este libro son propiedad exclusiva de sus respectivos due-
ños. Impreso en Argentina. Libro de edición argentina. Primera impresión realizada
en Sevagraf, Costa Rica 5226, Grand Bourg, Malvinas Argentinas, Pcia. de Buenos
Aires en octubre de MMIX.
ISBN 978-987-663-010-8
Iacono, Matías
Silverlight. - 1a ed. - Banfield - Lomas de Zamora : Gradi, 2009.
352 p. ; 24x17 cm. - (Manual users; 175)
ISBN 978-987-663-010-8
1. Informática. I. Título
CDD 005.3
00_Silverlight.qxp 9/30/09 1:16 PM Page 2
00_Silverlight.qxp 9/30/09 1:16 PM Page 3
4
PRELIMINARES
Matías Iacono
Ingeniero de sistemas, Microsoft Most Valuable Professional en
ASP.net, Orador Regional para INETA Latam, Scrum Master cer-
tificado y Microsoft Certified Technology Specialist. Cuenta con
más de quince años de experiencia en el desarrollo de software
con distintas tecnologías y metodologías.
Ha dictado cerca de cincuenta conferencias técnicas en distintos
países latinoamericanos, así como escrito y publicado artículos en
numerosas publicaciones internacionales.
Ha trabajado para empresas extranjeras de gran envergadura. En
la actualidad, se desempeña como ingeniero de software para Mo-
torola Argentina y es profesor en la Universidad Tecnológica Na-
cional de Córdoba.
Agradecimientos
Agradezco a todos los amigos que me brindaron su apoyo y sus
opiniones sobre lo escrito. A Miguel Saez, de Microsoft, por ha-
berme facilitado material y a Lucas Ontivero, de Motorola Ar-
gentina, por su crítica aguda, que me ayudó con el contenido pro-
puesto en el libro.
Dedicatoria
A mi familia, por quedarse a mi lado largos fines de semana mien-
tras concluía este libro.
00_Silverlight.qxp 9/30/09 1:16 PM Page 4
5
PRÓLOGO
Si hay algo a lo que le debemos la actual difusión de la tecnología informática, tan-
to dentro del hogar como de las oficinas, es a la continua evolución de las interfa-
ces gráficas de usuarios (GUI). Gracias a ellas, personas de todas las edades y pro-
fesiones, en todo el mundo, pueden interactuar con equipos de computación para
fines tan diversos como entretenerse, obtener información, realizar cálculos y co-
municarse, entre un sinnúmero de otras posibilidades.
Es seguro que tanto la constante innovación en el desarrollo de las interfaces grá-
ficas como la aparición de Internet han sido los catalizadores para uno de los más
fabulosos cambios en la manera en que las personas, alrededor del globo, se rela-
cionan mediante el uso de la tecnología.
Mientras que la Web seguirá siendo el ámbito de comunicación del futuro, es de es-
perar que los requerimientos de interactividad entre máquinas y humanos se vuel-
van aún más sofisticados y exigentes. Ante esto, Microsoft desarrolló Silverlight, una
nueva apuesta para el desarrollo de elementos de gráficos de interacción con los usua-
rios orientados a la Web.
En este aspecto es, justamente, en el que esta obra hace un gran aporte, al presentar
Silverlight 2.0 de una manera amena, clara y completa. En ella, se abarcan no sólo
los pormenores técnicos de la tecnología, sino que, además, el autor se ha esmerado
en brindar al lector un cúmulo de conocimientos que sólo podría obtenerse mediante
la experiencia, todo esto reflejado en tips, datos útiles, recomendaciones, curiosida-
des, advertencias y todos los consejos que el lector reconocerá como invaluables a la
hora de adentrarse en esta apasionante tecnología.
Por último, quisiera agradecer a Matías Iacono por este maravilloso trabajo que ha
sido una guía segura en el aprendizaje de Silverlight y, con cuya lectura y estudio,
me he sentido guiado y acompañado siempre.
Lucas Ontivero
Ingeniero de software,
Motorola Argentina
Prólogo
00_Silverlight.qxp 9/30/09 1:16 PM Page 5
PRELIMINARES
66
EL LIBRO DE UN VISTAZO
En esta obra se verán los conceptos principales para dominar Silverlight, la tecnología de
Microsoft orientada al desarrollo de contenido dinámico y animaciones para la Web. El contenido
está dirigido a desarrolladores con conocimiento de Microsoft .Net Framework, C# como lenguaje
principal, y que dominen algunos conceptos de JavaScript y HTML.
Capítulo 1
INTRODUCCIÓN A SILVERLIGHT 2
Para conocer Silverlight desde sus comienzos,
en este capítulo describiremos
su arquitectura. Hablaremos de las diferencias
entre aplicaciones tradicionales y las nuevas
aplicaciones visuales, y conoceremos la lista
de herramientas necesarias para poder
desarrollar aplicaciones Silverlight.
Capítulo 2
MICROSOFT EXPRESSION BLEND 2
En este capítulo nos enfocaremos
en Microsoft Expression Blend 2 como
herramienta de desarrollo para Silverlight,
orientada a diseñadores visuales
y a diagramadores de aplicaciones. Daremos
un paseo por la interfaz de Microsoft
Expression Blend 2 y crearemos nuestra
primera aplicación Silverlight. Este capítulo
ayudará a los diseñadores y desarrolladores
a entender cada uno de estos mundos.
Capítulo 3
EL MEJOR TRABAJO, CON LA MEJOR
HERRAMIENTA
Luego de enfocarnos en el diseñador visual,
centraremos la atención de este capítulo
en el desarrollador. Para esto, veremos
qué posibilidades nos ofrece Microsoft Visual
Studio 2008 para desarrollar aplicaciones
Silverlight, los controles y componentes
propuestos, su interfaz visual y los diferentes
tipos de proyectos disponibles desde este
entorno de desarrollo.
Capítulo 4
XAML AL EXTREMO
Cada uno de los controles y componentes
proporcionados por Silverlight,
su funcionalidad, eventos, métodos
y funciones, serán vistos en este capítulo.
Cada uno de estos elementos será descripto
con profundidad, generando código
de ejemplo por cada uno de ellos.
Este capítulo representa una excelente guía
de referencia sobre todos los componentes
disponibles en Silverlight.
Capítulo 5
LUZ, CÁMARA, ACCIÓN
Gran parte de las prestaciones otorgadas
por Silverlight incluyen la posibilidad
de mover objetos dentro de nuestra aplicación.
En este capítulo veremos cómo manipular esta
característica, ya que se explicarán
los distintos modelos disponibles para
animaciones y transformaciones dentro
de las aplicaciones Silverlight.
Capítulo 6
CERRAR EL CÍRCULO
Silverlight también otorga mucho potencial
con el manejo de imágenes, video y sonido.
En este capítulo hablaremos de ciertas
características relacionadas con actividades
00_Silverlight.qxp 9/30/09 1:16 PM Page 6
El libro de un vistazo
7
!
A lo largo de este manual encontrará una serie de recuadros que le brindarán información
complementaria: curiosidades, trucos, ideas y consejos sobre los temas tratados.
Cada recuadro está identificado con uno de los siguientes iconos:
INFORMACIÓN COMPLEMENTARIA
CURIOSIDADES
E IDEAS
DATOS ÚTILES
Y NOVEDADES
ATENCIÓN SITIOS WEB
RRR,_`
como consumir videos, mostrar imágenes
o tocar sonidos dentro de las aplicaciones.
También hablaremos de Deep Zoom
y sus características, así como del dibujo
a mano alzada con InkPresenter.
Capítulo 7
INTERCONEXIÓN
Este capítulo ofrece funcionalidades
altamente valiosas. Crearemos un juego
desde código C# y un lector de RSS,
usaremos almacenamiento aislado para
guardar información en el cliente, crearemos
aplicaciones para subir archivos al servidor
y culminaremos con la implementación
de la última tecnología de interoperabilidad
propuesta por Microsoft al conectar Silverlight
con Windows Communication Foundation.
Capítulo 8
EL NAVEGADOR Y SU DOMINIO
Silverlight se ejecuta dentro de una página
HTML manejada por el navegador web.
Por tal motivo, posee gran potencial
de interacción con el cliente. En este capítulo
veremos cómo Silverlight puede manipular
HTML así como intercambiar información
con JavaScript. Además, conoceremos cómo
JavaScript es capaz de consumir servicios
generados desde Silverlight.
Apéndice A
SILVERLIGHT FUERA DE WINDOWS
Gracias a MoonLight, Silverlight puede salir
de Windows y trabajar en sistemas
operativos basados en Linux y Unix.
Hablaremos del proyecto MoonLight,
sus características, limitaciones y el futuro
de Silverlight como tecnología fuera
de su ambiente nativo. Además, se presentan
algunas herramientas gratuitas y de código
libre que nos ayudarán en el desarrollo,
tanto para Windows como para Linux.
Apéndice B
SILVERLIGHT 3, LA NUEVA GENERACIÓN
Daremos un vistazo al producto recientemente
lanzado por Microsoft. Silverlight 3 trae
consigo valiosas mejoras al modelo
ya planteado, las que enumeraremos para
ganar conocimiento adicional por sobre
lo ya aprendido durante todo el libro.
Servicios al lector
En esta última sección, encontraremos
un índice que nos ayudará a buscar de forma
rápida los términos más importantes de esta
obra. Además, veremos un listado de sitios
de interés para ampliar nuestros
conocimientos y mantenernos al tanto
de las últimas novedades en la materia.
00_Silverlight.qxp 9/30/09 1:16 PM Page 7
00_Silverlight.qxp 9/30/09 1:16 PM Page 8
Contenido
9
Sobre el autor 4
Prólogo 5
El libro de un vistazo 6
Información complementaria 7
Introducción 12
Capítulo 1
INTRODUCCIÓN A SILVERLIGHT 2
Iniciarse en el mundo de Silverlight 2 14
Navegar hacia el mundo
de Silverlight 2 14
La experiencia de usuario
y la portabilidad 16
Arquitectura de Silverlight 2 19
Microsoft .Net Framework 20
Interfaz de usuario y presentación 21
El código XAML 22
Herramientas de desarrollo
para Silverlight 2 24
Resumen 27
Actividades 28
Capítulo 2
MICROSOFT EXPRESSION BLEND 2
Un paseo por Expression Blend 2 30
Silverlight 2 con Expression Blend 2 30
Unir los extremos 32
Un recorrido por Expression Blend 2 37
Explorador de soluciones 38
Página inicial de Silverlight 2 39
La página App.xaml 40
El entorno de Expression Blend 2 43
La barra de herramientas 46
Crear nuestra primera aplicación
con Expression Blend 2 48
Resumen 53
Actividades 54
Capítulo 3
EL MEJOR TRABAJO,
CON LA MEJOR HERRAMIENTA
Silverlight para desarrolladores 56
Puesta a punto de Visual Studio 2008 56
Silverlight 2 con Visual Studio 59
Crear la primera aplicación
con Visual Studio 2008 63
Interoperabilidad con
Expression Blend 2 76
Resumen 79
Actividades 80
Capítulo 4
XAML AL EXTREMO
El lenguaje XAML 82
¿Qué es XAML? 82
Declaración de objetos 82
Controles y componentes 83
Controles contenedores y agrupadores 84
Control Grid 84
Control GridSplitter 89
Control Canvas 92
Control StackPanel 95
Control ScrollViewer 98
Control Border 101
Controles de interacción con el usuario 103
CONTENIDO
00_Silverlight.qxp 9/30/09 1:16 PM Page 9
PRELIMINARES
10
Control Button 103
Control CheckBox 106
Control RadioButton 110
Control HyperlinkButton 113
Control Image 114
Control ComboBox 117
Control ListBox 124
Control TextBlock 126
Control TextBox 127
Control PasswordBox 130
Control DataGrid 132
Control Calendar 139
Control DatePicker 147
Control ProgressBar 148
Control Slider 152
Resumen 153
Actividades 154
Capítulo 5
LUZ, CÁMARA, ACCIÓN
Mover objetos 156
Transformaciones 158
Transformación de traslación 159
Transformación de rotación 161
Transformación escalar 165
Transformación de distorsión 167
Aplicar todas las transformaciones 168
Animaciones 170
DoubleAnimation 171
ColorAnimation 173
Animaciones y transformaciones 175
Estilos y plantillas 178
Estilos 178
Plantillas 182
Resumen 185
Actividades 186
Capítulo 6
CERRAR EL CÍRCULO
MediaElement 188
Ejecutar sonidos 188
Video 194
Elementos con video embebido 195
Marcadores de video 196
Deep Zoom 199
Crear el primer Deep Zoom 200
Incluir Deep Zoom en Silverlight 203
Dibujar con InkPresenter 208
Dibujar en forma manual 212
Dibujar sobre otros elementos 215
InkPresenter y áreas de dibujo 217
Resumen 219
Actividades 220
Capítulo 7
INTERCONEXIÓN
Ampliar las funcionalidades 222
Silverlight desde C# 222
00_Silverlight.qxp 9/30/09 1:16 PM Page 10
Contenido
11
WebClient 230
Enviar información 233
Almacenamiento aislado 239
Implementar el almacenamiento
aislado 240
Capacidad de almacenamiento 245
Almacenar configuraciones 247
OpenFileDialog 251
Manejo de hilos 255
El concepto de hilos 256
Temporizador 257
Personalizar los hilos 259
Hilos y eventos 261
Consumir servicios
desde Silverlight 263
Crear un servicio WCF 270
Manipular datos 275
Enlazado de datos 276
LinQ 283
Resumen 287
Actividades 288
Capítulo 8
EL NAVEGADOR Y SU DOMINIO
Conectar tecnologías 290
Silverlight 2 y el HTML 290
HtmlDocument y HtmlElement 292
HtmlPage 301
HtmlWindow 307
Cookies 316
Modificar CSS 320
Silverlight 2 y JavaScript 323
Llamar funciones 325
Objetos Silverlight
para JavaScript 327
Resumen 347
Actividades 348
Apéndice A
SILVERLIGHT FUERA
DE WINDOWS
Proyecto Moonlight 330
Sistemas operativos 330
Versiones de Moonlight 331
Herramientas de desarrollo 331
Problemas conocidos 333
Apéndice B
SILVERLIGHT 3, LA NUEVA GENERACIÓN
Silverlight 3 336
Nuevos controles 336
Efectos en tres dimensiones 337
Uso de Pixel Shader 338
Fuera del navegador 339
Servicios al lector
Índice temático 342
Sitios web recomendados 345
00_Silverlight.qxp 9/30/09 1:16 PM Page 11
INTRODUCCIÓN
Este libro está orientado a desarrolladores de software, y diseñadores visuales y grá-
ficos que deseen expandir su área de conocimiento de desarrollo hacia el ambiente
web. Un lector con nociones iniciales podrá ver, durante los capítulos, una evolu-
ción que le dará la oportunidad de aprender sin necesidad de saberes previos sobre
la tecnología propuesta, Silverlight, mientras que aquel lector con experiencia po-
drá encontrar en estas páginas una guía fundamental para aprender, con agilidad,
conceptos sobre esta tecnología de Microsoft. Sin embargo, es necesario, para am-
bos lectores, contar con conocimientos medios de desarrollo utilizando Microsoft
C#, así como las técnica primordiales del funcionamiento y ejecución de la Web.
Los temas propuestos en el libro fueron seleccionados para cubrir la mayor superfi-
cie de conceptos sobre Silverlight 2, presentados de una manera progresiva de tal
forma que el lector se sienta cómodo con su evolución y que aprenda a cada paso
que da. Desde la recomendación y el uso de las herramientas ideales para el desa-
rrollo bajo esta tecnología, tanto para diseñadores como para desarrolladores, gene-
ramos ejemplos prácticos en cada capítulo, que abarcan desde HTML hasta C#, así
como la aplicación de ASP.net y el uso de JavaScript.
Silverlight es un modelo en ebullición. En el momento de lanzarse la versión 1,
sus características eran limitadas; pero, al poco tiempo, Microsoft mejoró la tec-
nología y sacó a relucir la segunda versión de Silverlight, versión de la que se ocupa
este libro. Pero esta efervescencia, este cambio constante junto a la búsqueda de
un mejor producto y de una tecnología superior, hicieron que, durante el tiem-
po de escritura de este libro, Microsoft sacara la siguiente versión de Silverlight.
En este momento, ya contamos con la versión 3 de Silverlight como una versión
funcional y finalizada, por lo que incluimos un apartado, al final del libro, para in-
troducir al lector en algunas de las nuevas funcionalidades provistas por Silverlight 3.
De esta forma, con este texto, el lector no sólo aprenderá sobre Silverlight, sino
que tendrá un bono extra al final, que le servirá de rampa de lanzamiento para
abordar de lleno la nueva versión y permanecer siempre actualizado.
PRELIMINARES
12
00_Silverlight.qxp 9/30/09 1:16 PM Page 12
Introducción
a Silverlight 2
Iniciarse en el mundo
de Silverlight 2 14
Navegar hacia el mundo
de Silverlight 2 14
La experiencia de usuario
y la portabilidad 16
Arquitectura de Silverlight 2 19
Microsoft .Net Framework 20
Interfaz de usuario
y presentación 21
El código XAML 22
Herramientas de desarrollo
para Silverlight 2 24
Resumen 27
Actividades 28
Capítulo 1
En este primer capítulo veremos
el porqué de Silverlight 2, al mismo
tiempo que hablaremos de problemas
comunes en el desarrollo de software
desde la óptica de las interfaces gráficas,
los diseñadores y programadores,
así como las limitaciones
de las herramientas usadas por cada uno.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
01_Silverlight.qxp 9/30/09 1:20 PM Page 13
INICIARSE EN EL MUNDO DE SILVERLIGHT 2
Muchos cambios se han producido en el desarrollo web desde sus inicios. Se han
sucedido mejoras sustanciales hasta la llegada de la Web 2.0 y, sin embargo, se si-
guen buscando mejores formas y herramientas para trabajar en este fascinante mun-
do. Recorramos esos años de evolución hasta la actualidad, cuando una de estas
herramientas ve la luz para traer una solución a nuevas necesidades. Veamos, en
este capítulo, los componentes clave de Silverlight 2: las herramientas de desarro-
llo y diseño, su arquitectura y los elementos principales que le dan vida.
Navegar hacia el mundo de Silverlight 2
Desde los inicios de la Web, ésta ha ido evolucionando, mutando y creciendo.
Esta evolución se inició con la simple transferencia de texto, pasó por las imáge-
nes y la captura de datos del usuario por parte del sistema, hasta llegar al manejo
de contenido personalizado. Éste se genera para el usuario y por él, simulando
casi el mismo comportamiento de aplicaciones desarrolladas para sistemas de es-
critorio. Los cambios radicales en las tasas de transferencias de datos, así como
en las capacidades de los equipos que servían esta información, también acom-
pañaron dichos acontecimientos. Por supuesto, esta evolución no sólo fue de capa-
cidades de hardware y prestaciones hacia el usuario. Al mismo tiempo, estuvo acom-
pañada por software, lenguajes de programación y herramientas de desarrollo que,
en conjunto, ayudaran a amortiguar la curva de complejidad sobre las necesida-
des crecientes que tenían los sistemas. En definitiva, existían mayores requeri-
mientos por parte de los usuarios y de los sistemas, por lo que la implementación
en líneas de código y la puesta en marcha de los servicios necesitaron de herra-
mientas que hicieran más simple este trabajo.
En la actualidad, el desarrollo web está más pujante que nunca. Además, con el
advenimiento de teorías (y prácticas) como el Cloud Computing o servicios de
Internet totalmente dinámicos para correos electrónicos, confección de docu-
mentos, redes sociales e interconexión de servicios, entre otros, debemos enten-
der que la Web seguirá creciendo y mejorando durante mucho más tiempo. Esto
nos llevará de vuelta a la idea antes tratada: mayor complejidad, mejoramiento en
las herramientas y el soporte. Esta mejora en las herramientas que brindan soporte
tanto al desarrollador como al diseñador se hace cada vez más necesaria y es mu-
cho más requeridas por aquellos que se ven involucrados en el desarrollo web. De-
bido a que desarrollar para la Web no se restringe al uso de una tecnología única
y definitiva, el desarrollador web se ve en la necesidad imperativa de adquirir do-
minio y conocimientos sobre decenas de tecnologías y lenguajes de programación,
como XML, HTML, CSS, JavaScript, ActionScript, Lingo, PHP, C# y Java,
entre muchas otras que forman el conjunto de la Web. Y es aquí donde se hace
1. INTRODUCCIÓN A SILVERLIGHT 2
14
01_Silverlight.qxp 9/30/09 1:20 PM Page 14
visible Silverlight. Este software forma parte de dicho crecimiento y sirve como
solución, ya que plantea una mejor forma de desarrollar contenido dinámico pa-
ra la Web. Esto sucede no sólo en lo visual, sino también como herramienta de
desarrollo basado en tecnologías comunes ya conocidas.
No debemos equivocarnos al pensar que Silverlight constituye la estrategia de
Microsoft para competir con el ya popular Flash, ex de Macromedia, y ahora de
Adobe. Por el contrario, Silverlight representa una oportunidad de reutilizar el co-
nocimiento ya adquirido sobre código basado en Microsoft.Net Framework, un
modelo que soporta no sólo lenguajes desarrollados y mantenidos por esta empresa,
sino que cuenta, por el contrario, con el soporte de compañías creadoras de lengua-
jes tan populares como Borland C# Builder y Delphi, también de Borland. De es-
ta forma, Silverlight trae consigo la posibilidad de enriquecer la experiencia visual
en el cliente web, trabajando en cualquiera de los navegadores de Internet más
conocidos. Puede interactuar y ser modificado por lenguajes como JavaScript, ex-
tendiendo el concepto de HTML dinámico y A.J.A.X. (Asynchronous JavaScript and
XML o, en castellano, JavaScript asíncrono y XML). También puede consumir ser-
vicios web o cualquier elemento con la capacidad de retornar XML, al mismo tiempo
que puede ser programado o desarrollado mediante aquel lenguaje que usamos to-
dos los días para nuestros desarrollos, o con el que nos sintamos más cómodos para
generar las líneas de código que darán vida a nuestra aplicación.
Figura 1. Microsoft .Net Framework es el nexo entre el sistema
operativo y nuestro código. Nos ofrece una plataforma de ejecución, librerías
de código, acceso a datos y soporte para diferentes lenguajes.
VB C++ C# J# ...
Common Language Specification
VisualStudio.NET
ADO .NET y XML
Librería de clases base
Common Language Runtime
Sistema Operativo
ASP .NET
Web Forms • Web Services
Mobile Internet Toolkit
Windows
Forms
Iniciarse en el mundo de Silverlight 2
15
01_Silverlight.qxp 9/30/09 1:20 PM Page 15
La experiencia de usuario y la portabilidad
Antes de la aparición de Microsoft .Net Framework, construir una aplicación de soft-
ware requería diferentes habilidades y dependía del ambiente en el cual se desarrollara
esta aplicación. Así, si las aplicaciones necesitaban desarrollarse para ser usadas bajo
Windows, éstas requerían que su diseño visual se creara de manera especial para este
modelo. Al mismo tiempo, debería contemplar las limitaciones que el lenguaje de pro-
gramación trajera consigo. El diseño, entonces, quedaba encapsulado dentro del códi-
go del lenguaje seleccionado, siendo casi imposible su implementación en otro lenguaje
o en una nueva versión del mismo. Pensemos que, si una aplicación debía ser migrada
a una nueva versión del lenguaje o, por necesidades de negocio, debía ser implemen-
tada en otro lenguaje, toda la interfaz visual debía ser reescrita e implementada. A lo
anterior debíamos sumar que, si existía un cambio de ambiente, es decir, si movíamos
el desarrollo a un dispositivo móvil o a la Web, no sólo la interfaz debía ser reescrita,
sino que también debía cambiar la lógica radicada en el código. Esto no sólo acarrea
reinversión de tiempo y dinero, sino que, además, la interfaz (y tal vez la lógica de ne-
gocio) nunca quedaría del todo igual, castigando la experiencia del usuario que se ha-
bía acostumbrado a una herramienta ya construida e implementada.
Con la primera versión del .Net Framework, Microsoft hace el intento inicial de
generar portabilidad entre ambientes y lenguajes, separando la interfaz gráfica del
lenguaje de programación y proveyendo componentes comunes para que los am-
bientes similares puedan reutilizar las interfaces ya creadas. Gracias a esto, teníamos
aplicaciones creadas para Windows, que también funcionaban en dispositivos móviles,
aunque aún quedaba trabajo por hacer en cuanto a desarrollo web y Windows,
ya que estos dos ambientes seguían siendo incompatibles. Con la versión 3.0 de
Microsoft .Net Framework, se introdujo un nuevo enfoque por medio de un es-
quema XML para la confección y manipulación de interfaces de usuarios: ya no
aparecían los típicos botones y cajas de texto rígidas comunes en cualquier aplica-
ción de escritorio. Este esquema, llamado XAML (eXtensive Application Markup
Language, o en castellano, Lenguaje Extensible de Formato para Aplicaciones) por
sus siglas en inglés, le permitió al desarrollador crear otro tipo de aplicaciones a
nivel visual. XAML fue explotado por WPF (Windows Presentation Foundation),
pero muy rápido se entendió que XAML tenía mucho futuro por delante.
1. INTRODUCCIÓN A SILVERLIGHT 2
16
,
La experiencia demuestra que la primera reacción por parte de los desarrolladores al ver
Silverlight es asociarlo en forma directa con la competencia de Adobe Flash. Silverlight persigue
objetivos similares, pero se separa de Adobe Flash en ciertos aspectos técnicos, como lengua-
jes de programación y arquitectura.
¿QUÉ ES SILVERLIGHT?
01_Silverlight.qxp 9/30/09 1:20 PM Page 16
Figura 2. CardSpace, WCF, WPF y WF (Workflow Foundation)
se agregan como parte de Framework 3 sobre la versión 2 de Framework.
Silverlight 2 usa, para la representación visual de sus elementos, XAML. Las mis-
mas etiquetas que, como decíamos antes, también son soportadas por aplicaciones
de escritorio construidas con WPF. Esto genera una ventaja significativa sobre la
creación de aplicaciones y la adaptación del usuario a nuevas tecnologías. Pen-
semos que, al tener un componente común como XAML para la representación
visual de elementos de la interfaz gráfica, el esfuerzo aplicado para la creación de
uno de estos componentes puede ser reutilizado y explotado en otros ambientes,
no sólo en aquel para el cual Silverlight fue ideado. Pensemos entonces en una
aplicación de escritorio, con cientos de usuarios que la usan durante meses o años
y, de un momento a otro, se encuentran usando la misma aplicación, pero den-
tro de un navegador web, con los mismos botones, el mismo contenido visual e
igual comportamiento. Uno de los lados más rugosos en la implementación de un
sistema está atado a la adopción de éste por parte del usuario, y es en los cambios
de plataformas y ambientes donde se producen las discordias. Aquí es necesario
Microsoft
.NET Framework
Versión 2.0
CardSpace WPF
WCFWF
Iniciarse en el mundo de Silverlight 2
17
_`
Microsoft .Net Framework no sólo soporta los lenguajes de programación propuestos por Mi-
crosoft. También podemos encontrar otros como Boo, Icc, Clarion#, Cobol, Corba, Eiffel, Fortran,
Lisp, PHP, Perl y más. Esto puede resultar en especial interesante, ya que no necesitamos apren-
der un nuevo lenguaje para desarrollar en Microsoft .Net Framework.
MICROSOFT .NET Y LENGUAJES
01_Silverlight.qxp 9/30/09 1:20 PM Page 17
invertir mayor esfuerzo para que esta nueva idea sea aceptada. Por tal motivo, nos
hará falta toda la ayuda posible al momento de hacer este cambio.
En la Web, las aplicaciones tienen más representatividad y, por ende, su atractivo
y su facilidad de uso necesitan potenciarse. Esta mejora es llevada a cabo por la
implementación de soluciones que conjugan JavaScript y XML, dando como pro-
ducto la pieza conocida como A.J.A.X., donde bien podemos encontrar cientos de
modelos listos para ser implementados. Pero el desarrollo sigue enfocándose en la
manipulación del HTML que, sin desmerecer sus posibilidades, siempre llegará a
un techo máximo, relacionado con las capacidades del mismo modelo HTML. En
comparación con el modelo de aplicaciones de escritorio, la interactividad ofrecida
por este último es muy superior a la que presenta HTML, y es aquí donde Silverlight,
una vez más, explota lo mejor de estos dos mundos y lo lleva en forma directa al
ámbito de aquel que pierde en comparación: el del HTML.
Figura 3. Silverlight se nutre de cada una de las principales
características de los dos mundos, generando una mejor experiencia
de usuario e independencia en plataformas.
Navegadores web
CSS/HTML
JavaScript/AJAX
ASP.net
Aplicaciones
de escritorio
XAML
Framework .Net
1. INTRODUCCIÓN A SILVERLIGHT 2
18
RRR
Es importante entender las diferencias entre las versiones de Microsoft .Net Framework. Sólo a
partir de la versión 3, se incorpora el uso de XAML, así como WPF, pero el núcleo de este Fra-
mework se mantiene idéntico al de la versión 2. Al desarrollar para cualquiera de estas nuevas
plataformas, deberemos elegir una versión de Framework 3 o superior.
VERSIONES DE MICROSOFT .NET FRAMEWORK
01_Silverlight.qxp 9/30/09 1:20 PM Page 18
Como observamos en la Figura 3, Silverlight toma lo mejor de los dos mundos. Por
un lado, los controles y componentes versátiles propuestos por el desarrollo de es-
critorio y, por el otro, la portabilidad entre plataformas y la rapidez de la actuali-
zación de aplicaciones a miles de usuarios al mismo tiempo que otorga Internet.
Esta versatilidad y portabilidad entre plataformas, tanto de escritorio como web,
no sería posible sin un lenguaje común de representación de controles.
XAML es el lenguaje que nos dará esta posibilidad no sólo para el desarrollo, sino
que también brinda la oportunidad de aumentar la versatilidad de las interfaces,
poder llevar el comportamiento de las aplicaciones de escritorio a la Web, posibi-
litar la adopción por parte del usuario final de manera independiente del sistema,
mediante el aumento de la calidad y de la velocidad en el desarrollo, y otros pun-
tos ganados con la utilización de XAML y Silverlight.
Arquitectura de Silverlight 2
Al comienzo de nuestro recorrido, nombramos algunas de las características de Sil-
verlight que, al mismo tiempo, definen su planteo arquitectónico. Dijimos que
Silverlight está enfocado a la Web y que es ejecutado por el navegador web. Es-
to se consigue gracias a un plugin o aditivo que hará las veces de gestor o in-
térprete. Este componente ronda los 5 megabytes, lo que constituye una suma
muy pequeña en relación con su potencia. En la actualidad, es soportado por los
principales navegadores de Internet como Internet Explorer, FireFox y Safari,
así como los sistemas operativos Windows (con base en Windows XP con Service
Pack 2 y hasta Windows 7), Mac OS X 10+ y Linux.
Pero Silverlight, aunque hemos hecho hincapié en la gestión de interfaces de usuario,
no sólo es un lienzo donde podemos crear animaciones vectoriales, sino, muy por el
contrario, consiste en una plataforma liviana de desarrollo con soporte para SOA
(Service Oriented Architecture o, en castellano, Arquitectura Orientada a Servicios), re-
des, manejo de datos, y más. Como observamos en la Figura 4, Silverlight va mucho
más allá y nos entrega, por sobre todas las cosas, acceso a las últimas tecnologías y
patrones de desarrollo de software. Podemos separar y enumerar las diferentes carac-
terísticas sobre la base de su área de trabajo, como veremos a continuación.
Iniciarse en el mundo de Silverlight 2
19
_`
Por lo general, es difícil lograr que un usuario adopte una nueva aplicación cuando está acos-
tumbrado a la que usa desde hace años. Este problema de adopción se ve potenciado en quienes
nunca usaron una computadora. Pero, si podemos reproducir en el ordenador lo que el usuario
está acostumbrado a utilizar en la vida real, la adopción será casi transparente.
LA DIFÍCIL ADOPCIÓN POR PARTE DE LOS USUARIOS
01_Silverlight.qxp 9/30/09 1:20 PM Page 19
Figura 4. En este diagrama podemos observar
la arquitectura soporte completa de Silverlight 2.
Microsoft .Net Framework
Con respecto a las líneas de código y de clases ya implementadas para ser usadas por
el desarrollador de código, el Framework disponible cubre todas las áreas necesarias
para interactuar con datos y hasta con lenguajes propios de la Web.
.NET para Silverlight
Centro de presentación
Manejo de navegador
WCF
REST
RSS/ATOM
SOAP
Librería para
Microsoft
AJAX
Motor
JavaScript
POX
JSON
WPF
Controls
Data Binding
Layout
Editing
Data
Motor de ejecución CLR
XAML
LINQ
XLINQ
XML
Centro de interfaz
gráfica
Vector
Animation
Text
Images
Integrado
con la red
Integrado
con DOM
Servicio
de aplicaciones
Instalador
Periféricos
Keyboard
Mouse
Ink
Multimedia
VC1
WMA
MP3
DRM
Media
BCC
Generics
Collections
Cryptography
Threading
DLR
Iron Python
Iron Ruby
Jscript
1. INTRODUCCIÓN A SILVERLIGHT 2
20
01_Silverlight.qxp 9/30/09 1:20 PM Page 20
• LinQ y XLinQ: soporte especializado para llevar a cabo el manejo de colec-
ciones de objetos, acceso a datos y XML. Con LinQ podremos crear consultas
integradas con el lenguaje de programación.
• WCF (Windows Communication Foundation): plataforma de comunicación para
acceso a servicios web, servicios remotos y peticiones HTTP, entre otros.
• Librería de clases base: acceso a las librerías de clases de Microsoft .Net Frame-
work, que nos ofrece soporte para el manejo de cadenas de texto, expresiones regu-
lares, serialización de datos, manejo de internacionalización de aplicaciones y más.
• CLR (Common Language Runtime): motor de Microsoft .Net que se encarga del
manejo de la memoria y demás puntos de contacto con el sistema operativo.
• DLR (Dynamic Language Runtime, en castellano Lenguajes Dinámicos): soporte pa-
ra lenguajes de programación como JavaScript, Iron Phyton e Iron Ruby.
• Almacenamiento aislado: permite generar sectores de almacenamiento de archi-
vos e información de manera aislada y para usuarios específicos.
Interfaz de usuario y presentación
Silverlight también presenta una gran cantidad de funcionalidad en cuanto a su pre-
sentación visual y puede manejar sonidos, imágenes y videos, así como una serie de
controles y componentes listos para usar.
• Video y sonido: inclusión de soporte de formatos de video y sonido comunes co-
mo MP3 y WMA. Incluye capacidades de streaming.
• Imágenes: capacidad de despliegue de imágenes tanto vectoriales como mapas de
bits en sus formatos más comunes, texto y animaciones.
• Enlazado de datos: capacidad de enlazado de fuentes de datos automática que fa-
cilita el despliegue de la información desde diferentes fuentes de datos.
• Controles: set de controles listos para usar que brindan la posibilidad de crear
nuestro propio set de controles y de reusarlos en diferentes aplicaciones.
• XAML: implementación de eXtensible Application Markup Language para la con-
fección de las interfaces. Éstas son creadas sobre la base de XML.
Como pudimos ver hasta aquí, Silverlight no es un simple visualizador de ani-
maciones, sino un avanzado complemento de desarrollo que hace uso de las
principales tecnologías Microsoft y que permite desenvolvernos con soltura al
momento de desarrollar aplicaciones sobre éste.
Silverlight, entonces, nos ofrece la potencia de los lenguajes de programación uti-
lizados, por lo general, en el desarrollo de aplicaciones de escritorio y web, ade-
más, de su posibilidad de interacción con bases de datos y servicios remotos.
También, nos brinda la elegancia de sus vistosas interfaces visuales, que pueden
interactuar con lenguajes cliente, tales como JavaScript, enmarcado en un nave-
gador web, sin estar atado a un sistema operativo ni a un navegador específico.
Iniciarse en el mundo de Silverlight 2
21
01_Silverlight.qxp 9/30/09 1:20 PM Page 21
Figura 5. En la imagen, observamos los controles
visuales listos para usar y su apariencia por defecto.
El código XAML
Ya hemos nombrado a XAML como uno de los componentes fundamentales de
Silverlight, pero veamos un poco más en profundidad de qué se trata exactamen-
te. XAML es un lenguaje declarativo, formado por etiquetas descriptivas para
cada uno de los componentes que Silverlight pueda representar. XAML basa el
concepto descriptivo en el conocido modelo de XML. Gracias a esta cualidad (ba-
se de XML), entender la estructura de XAML resulta simple e intuitivo. Veamos
a continuación un ejemplo de elementos XML simples:
1. INTRODUCCIÓN A SILVERLIGHT 2
22
RRR
Debido a que Silverlight puede ser desarrollado con los principales lenguajes de programación
soportados por Microsoft .Net Framework, éste brinda pleno soporte para la programación orien-
tada a objetos y puede absorber todos los beneficios inherentes a este modelo de programación.
PROGRAMACIÓN PROFESIONAL
01_Silverlight.qxp 9/30/09 1:20 PM Page 22
<Contenedor>
<Elemento Atributo=”Valor”>
Contenido del Elemento
</Elemento>
</Contenedor>
Etiquetas o tags descriptivas dentro de caracteres < y >. Cada elemento es iniciado con
un nombre específico y siempre deberemos señalar su cierre utilizando el mismo nom-
bre más los caracteres </, lo que especificará la finalización del tag. En el ejemplo, tam-
bién podemos notar cómo un elemento puede contener otros elementos, así como atri-
butos descriptivos y valores dentro del mismo nodo. XAML sigue este mismo patrón:
<Canvas Width=”300” Height=”300” Background=”Brown”>
<TextBlock x:Name=”Texto” Text=”Hola
Mundo!”></TextBlock>
</Canvas>
El ejemplo en XAML nos demuestra que la estructura es similar al del que hemos
usado para XML, con la salvedad de que las etiquetas o tags ya se encuentran defi-
nidas y asociadas a los elementos visuales que representan. En el ejemplo, colocamos
un contenedor que tendrá un tamaño en ancho y en alto de 300 pixeles, y color de
fondo azul. Dentro de este contenedor, encontramos otro control utilizado para la
visualización de textos, que mostrará la frase Hola Mundo! en pantalla.
Figura 6. Resultado de nuestra primera prueba con XAML y Silverlight.
Iniciarse en el mundo de Silverlight 2
23
01_Silverlight.qxp 9/30/09 1:20 PM Page 23
El ejemplo nos sirve, al mismo tiempo, para mostrar otros atributos importantes den-
tro del mundo de XAML y de Silverlight. Tanto el elemento Canvas como TextBlock
son controles preestablecidos por el entorno de Silverlight. Canvas es utilizado
para definir un elemento contenedor de otros componentes, y TextBlock nos da la
posibilidad de mostrar texto en pantalla en forma de bloques. La combinación de
estos elementos produce lo que aparece en la Figura 6, pero el concepto va más allá
porque muestra cómo, anidando elementos, podemos conseguir diferentes efectos
visuales. Así, es posible mezclar un control del tipo botón con un control utilizado
para mostrar imágenes o videos y obtener como resultado un botón en cuyo fondo
se reproduce un video. Por último, el atributo x:Name es el que le otorga, al con-
trol, la capacidad de tener un nombre único, descriptivo, que podrá ser usado por
el lenguaje de programación que elijamos para darle funcionalidad a la interfaz vi-
sual. Con este atributo, podremos cambiar el texto representado al principio en tiem-
po de ejecución, sobre la base de la reacción de un evento por parte del usuario o
por parte del flujo de nuestra aplicación. A medida que avancemos en el libro, nos
introduciremos dentro de XAML; también en los diferentes componentes y con-
troles disponibles por parte del entorno de desarrollo y librerías de objetos.
Herramientas de desarrollo para Silverlight 2
Si tenemos en cuenta que una de las principales cualidades de Silverlight es el poten-
ciamiento visual en interfaces de usuario, sería muy interesante contar con herramien-
tas para su correcto diseño y diagramación. Así, de manera sencilla, nos guiarían en la
confección de los elementos XAML, su estructura, controles anidados, enlazado a fuen-
tes de datos, entre otros. Microsoft nos provee de dos herramientas principales, cada
una de ellas enfocada a cubrir una de las ramas involucradas en la generación de ele-
mentos Silverlight. Por un lado, para desarrolladores de software, la herramienta por
excelencia es Microsoft Visual Studio en su versión 2008. Aunque la nueva versión
de esta herramienta puede obtenerse con facilidad (Visual Studio 10), la que hemos
nombrado es suficiente para emprender nuestra labor. Microsoft Visual Studio 2008
resultará ideal debido a su soporte de Microsoft .Net Framework 3.5, herramienta
que trae consigo una serie de plantillas para Silverlight 2.
1. INTRODUCCIÓN A SILVERLIGHT 2
24
RRR
Gracias a la extensibilidad de XML como lenguaje de etiquetas es que XAML genera un nuevo sub-
conjunto de estas etiquetas para la representación de controles en el entorno de Silverlight. Así
lo hace flexible en la creación de los elementos, fácil de entender y portable entre ambientes.
XAML Y XML
01_Silverlight.qxp 9/30/09 1:20 PM Page 24
Figura 7. Visual Studio 2008 otorga pleno soporte para
Silverlight 2 mediante plantillas como las que observamos en la imagen.
De cualquier manera, tendremos que instalar, además de la herramienta mencio-
nada, el Service Pack 1 para ésta. La instalación del Service Pack 1, junto con la de
las herramientas de desarrollo de Silverlight 2, incluirán en Visual Studio 2008 las
plantillas de la Figura 7. Debido a que la versión 2 de Silverlight vio la luz después
que la herramienta de desarrollo, este procedimiento resulta la única forma de po-
der ver los asistentes y demás componentes dentro de la mencionada herramienta.
Además de las plantillas que acelerarán el desarrollo, podremos encontrar una serie de
controles y componentes para su uso inmediato que, si bien, como veremos más ade-
lante, es posible construirlos por nuestra cuenta desde cero, toda la lógica de funcio-
nalidad ya se encuentra contenida y probada en ellos. Esto nos ahorra tiempo de tra-
bajo al no tener que desarrollar algo ya existente. Componentes como botones,
calendarios y cajas de texto son sólo algunos de los que encontraremos dentro del aba-
nico de posibilidades. Como vemos en la Figura 8, Visual Studio 2008 nos presenta una
lista completa de controles listos para usar que, como ya dijimos, tienen toda la lógica
que necesitarán impresa en el mismo componente, y, además, está pronta para usar.
Iniciarse en el mundo de Silverlight 2
25
Además del Service Pack 1 para Visual Studio 2008, también deberíamos contar con el con-
junto de herramientas de Silverlight. Éstas pueden ser descargadas desde la dirección
www.microsoft.com/downloads, ingresando Silverlight 2 tools for Visual Studio 2008 como
criterio de búsqueda.
DESCARGA DE SILVERLIGHT 2 TOOLS PARA VISUAL STUDIO 2008
01_Silverlight.qxp 9/30/09 1:20 PM Page 25
Figura 8. Grillas, cajas de texto y listas desplegables son sólo
algunos de los controles listos para usar incluidos en Visual Studio 2008.
Por otro lado, también existe una herramienta para diseñadores gráficos que no
cuenten con experiencia en el desarrollo de software. Con una interfaz similar a
la de herramientas para manejo fotográfico, Microsoft Expression Blend 2 le
permite al diseñador gráfico, y por qué no al desarrollador, construir XAML de
manera rápida y amigable, como toda herramienta WYSIWYG (What you see is
what you get o en castellano Lo que ves es lo que obtienes) por sus siglas en in-
glés. Esto quiere decir que, al trabajar con Microsoft Expression Blend 2, el
diseño que planteemos será igual al resultado final en el momento de ejecución
de la aplicación de Silverlight. Deberemos usar Microsoft Expression Blend 2 si
estamos habituados a la creación de imágenes vectoriales o si sólo buscamos ace-
lerar el desarrollo de componentes Silverlight. Veremos más a fondo las cualida-
des de Microsoft Expression Blend 2 a lo largo de los capítulos, con suficiente
detalle como para poder utilizarlo con cierta seguridad.
Por último, cabe mencionar que Microsoft Visual Studio 2008 y Microsoft Ex-
pression Blend 2 se compenetran de tal forma que, por lo común, nos veremos
creando código en la primera herramienta, abriendo y editando el mismo pro-
yecto en la segunda, para terminar con algunos retoques artísticos o acelerar el
enlazado de datos en nuestro trabajo. En la Figura 9, podemos observar cómo un
proyecto creado en Visual Studio 2008 puede ser abierto y manipulado en for-
ma directa con Microsoft Expression Blend 2.
Debido al mismo motivo citado en el caso de Visual Studio 2008, es necesario
instalar un conjunto de herramientas en Microsoft Expression Blend 2 para con-
tar con plantillas que den soporte a Silverlight 2. En este caso, el Service Pack 1
para Microsoft Expression Blend 2 nos otorgará la prestación.
1. INTRODUCCIÓN A SILVERLIGHT 2
26
01_Silverlight.qxp 9/30/09 1:20 PM Page 26
Figura 9. Microsoft Expression Blend 2 trabajando
sobre una solución creada en Microsoft Visual Studio 2008.
A lo largo del libro haremos referencia a estas dos herramientas, que serán usadas
para los distintos ejemplos que plantearemos. Por tal motivo, es recomendable con-
tar con las herramientas instaladas en nuestro equipo antes de continuar con los
siguientes capítulos. Es posible también realizar los ejemplos con las versiones gra-
tuitas de Visual Studio 2008 (Visual Studio 2008 Express), aunque no podemos
garantizar que los ejemplos de interfaz y otros aspectos concuerden con lo que los
usuarios de estas versiones verán en sus equipos.
Iniciarse en el mundo de Silverlight 2
27
… RESUMEN
Silverlight puede ser una herramienta extremadamente potente con soporte basado en
Microsoft .Net Framework, que nos otorga la posibilidad de desarrollar en el lenguaje y la forma
que mejor nos convenga. Desde la versión 1 de Silverlight hasta la actual, ha habido mejoras
notables, con mayor funcionalidad y prestaciones tanto para el desarrollador como para el
diseñador visual. El usuario final se ve beneficiado al tener que descargar un plugin de tamaño
pequeño y que trabaja en casi todos los navegadores y sistemas operativos de la actualidad.
01_Silverlight.qxp 9/30/09 1:20 PM Page 27
28

PREGUNTAS TEÓRICAS
1 ¿En qué modelo se basa el código XAML pa-
ra representar los elementos de la interfaz?
2 ¿Subconjunto de qué otro modelo de desa-
rrollo visual para Windows podríamos con-
siderar a Silverlight?
3 ¿Qué versión de Microsoft .Net Framework
necesitamos, como mínimo, para trabajar
con Silverlight 2.0?
4 ¿Qué sistemas operativos y navegadores
web soportan la ejecución de Silverlight 2.0?
5 ¿Qué herramienta resulta ideal para desa-
rrolladores, que les permita potenciar el
desarrollo de aplicaciones Silverlight 2.0?
6 ¿Los diseñadores visuales cuentan con al-
guna herramienta de software que los ayu-
de a crear contenido para Silverlight 2.0?
7 ¿Es necesario instalar algún aditamento en
la herramienta de desarrollo?
8 ¿Silverlight 2.0 provee algún conjunto de
componentes listos para usar?
9 ¿Por qué es importante crear interfaces
atractivas e intuitivas en las aplicaciones?
10¿Cómo se llama el modelo de desarrollo
para la Web que conjuga el uso de XML y
JavaScript?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Diríjase al sitio web de la W3C (www.
w3.org/XML) para aprender más sobre
XML.
2 Para introducirse mejor en el mundo de
Silverlight, intente ampliar el ejemplo pro-
puesto en este capítulo, modificando el
tipo de fuente y el color de fondo de la apli-
cación creada.
3 Para conocer más sobre desarrollo con
Microsoft .Net, tome el curso gratuito del
Desarrollador 5 Estrellas desde el sitio
web de Microsoft. Este curso ayuda a en-
tender términos utilizados en este libro. La
URL es www.mslatam.com/latam/msdn/
comunidad/dce2005.
4 Instale Microsoft Expression Blend 2 y
déjelo listo para trabajar en el siguiente
capítulo.
5 Una vez instalados Visual Studio 2008 y
Microsoft Expression Blend 2, ingrese en
www.silverlight.net, el sitio oficial de
Silverlight, descargue los ejemplos y
analícelos. Esto ayuda a entender con
mayor facilidad esta tecnología.
01_Silverlight.qxp 9/30/09 1:20 PM Page 28
Microsoft
Expression
Blend 2
Un paseo por Expression
Blend 2 30
Silverlight 2 con Expression
Blend 2 30
Unir los extremos 32
Un recorrido por Expression
Blend 2 37
Explorador de soluciones 38
Página inicial de Silverlight 2 39
La página App.xaml 40
El entorno de Expression
Blend 2 43
La barra de herramientas 46
Crear nuestra primera
aplicación con Expression
Blend 2 48
Resumen 53
Actividades 54
Capítulo 2
¿Cuáles son las herramientas disponibles
para desarrollar aplicaciones Silverlight?
¿Cómo podemos aumentar nuestra
productividad a la hora de escribir XAML?
Éstas son algunas de las preguntas
que abordaremos en este capítulo.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
02_Silverlight.qxp 9/30/09 1:23 PM Page 29
UN PASEO POR EXPRESSION BLEND 2
En el capítulo anterior, nos introdujimos en el mundo de Silverlight 2. Vimos
algunas de sus características, los elementos que lo componen y las principales he-
rramientas de desarrollo usadas para la creación de aplicaciones y componentes de
Silverlight. Una de estas herramientas, Microsoft Expression Blend 2, es usada
por los diseñadores visuales y por los desarrolladores como un suplemento para
los detalles visuales avanzados. En este capítulo, ahondaremos en el uso de esta
herramienta y su interacción con Silverlight 2, cómo crear animaciones así como
también elementos compuestos, para finalizar con la creación de nuestra primera
aplicación Silverlight 2. Este contenido está dirigido, en especial, a diseñadores
visuales que quieran incursionar en el uso de Expression Blend 2 como herramienta
de diseño para software y a desarrolladores de software que necesiten modificar, de
manera rápida, interfaces visuales basadas en XAML.
Silverlight 2 con Expression Blend 2
Desde los inicios de su desarrollo, este software siempre se enfocó, de manera
prioritaria, en las líneas de código y en la solución del problema propuesto. Es-
to sucede ya que, justamente, fueron el código y el problema por corregir los que
motivaron la creación de soluciones de software, que provean una respuesta
programática a la dificultad planteada. Este enfoque, el de la solución del problema,
causó que en el desarrollo de software primara la capacidad y la calidad de reso-
lución de un problema por encima del enfoque interactivo entre la aplicación y
el ejecutor de ese programa. Así, dentro de la historia del software y las compu-
tadoras, por carencias o por el enfoque antes citado, el trabajo se hacía mediante
tarjetas perforadas, las cuales se apilaban en grandes cajas y que poseían, en sí mis-
mas, la resolución de una de las partes que solucionaba el todo del problema. Sin
ninguna duda, este sistema era manejado sólo por el desarrollador de este software
primario y no por alguien ajeno a la informática de la época. Desde ese momen-
to de la historia y hasta la actualidad, se produjeron cambios en la manera en que
el usuario interactuaba entonces e interactúa ahora con esta pieza de software. Sin
2. MICROSOFT EXPRESSION BLEND 2
30
_`
A pesar de más de 40 años de evolución en la ingeniería de software, sólo en la actualidad se po-
ne especial énfasis en las interfaces visuales y en cómo éstas pueden ser parte de la solución
del problema al que el usuario se debe enfrentar a diario. Así, vemos aparecer nuevas tecnolo-
gías multitáctiles en sistemas operativos, o de captura de movimientos en consolas de juegos.
LA EVOLUCIÓN DE LAS INTERFACES
02_Silverlight.qxp 9/30/09 1:23 PM Page 30
embargo, éste seguiría encontrándose una y otra vez ante una herramienta que,
aunque en esencia cubriera sus necesidades funcionales y resolviera el dominio del
problema planteado, no abarcaría los conceptos de usabilidad, ergonomía visual
o interactividad entre el hombre y la máquina.
Figura 1. En el Mix 2009 realizado por Microsoft,
uno de los temas por tratar fue la creación de interfaces gráficas.
Después de algunas décadas marcadas por este comportamiento de parte de la
ingeniería de software y de aquellos que la han practicado, de alguna forma, el usuario
terminó acostumbrándose a la idea de obtener aplicaciones o piezas de software que
aparecen, como grandes hitos visuales y pantallas monocromáticas. Esto sucede,
incluso, en pleno auge de las tarjetas aceleradoras de video con capacidades vi-
suales que diez años atrás se reservaban sólo a inmensos ordenadores destinados a la
producción de efectos cinematográficos. Muy pocos desarrolladores de software
contemporáneos, incluidas las empresas, contemplan como parte de sus desarro-
llos la inclusión de esta temática. Sólo con la llegada de la Web, algunos de ellos
adicionaron esto como una necesidad comercial, pero, en muy pocos casos, co-
mo una realidad para brindar un mejor producto que, además de solucionar un
Un paseo por Expression Blend 2
31
,
Es importante incluir en los proyectos de desarrollo de software a un diseñador gráfico que
cuente con experiencia en interfaces de usuario. No debemos desestimar este punto en nues-
tros desarrollos. El éxito de nuestro producto no está marcado sólo por las líneas de código,
la usabilidad es un aspecto muy importante.
CONSULTEMOS A UN DISEÑADOR
02_Silverlight.qxp 9/30/09 1:23 PM Page 31
problema, resulte optimizado en lo que a interactividad con el usuario se refiere.
Por supuesto, la implantación de este concepto dentro del desarrollo de software
acarreó ciertos problemas que han tenido que ser resueltos por fuerza bruta más que
por inteligencia, debido a que la solución planteada, la de incorporar mejoras vi-
suales e interactivas, requiere de la presencia de otras ciencias. Esas ciencias están
alejadas del desarrollo de software, por lo que el problema resulta bastante claro al
tener que unir, de alguna forma, extremos que hablan idiomas diferentes.
Unir los extremos
En la actualidad, el mayor impedimento en la creación de aplicaciones visuales y
el trabajo realizado por los expertos en esta materia es causado por las herramien-
tas que éstos utilizan. Cuando en un proyecto de software es necesaria la interven-
ción de diseñadores gráficos especializados en experiencia de usuario, éstos plasman
su trabajo en herramientas más ligadas a las doctrinas del diseño gráfico y las artes
visuales que a las del desarrollo de software. Entonces, el problema recae en que
tanto el diseñador como el desarrollador hablan idiomas diferentes: los primeros
se refieren a colores, movimiento, disposición de elementos y formas, entre otros
aspectos, mientras que los segundos necesitan saber qué mostrar y cómo se reali-
zará el código que contenga la lógica. Al mismo tiempo, los diseñadores suelen
desconocer las limitaciones de las plataformas donde serán creados los productos
de software y tienden a generar elementos visuales extremadamente atractivos, pe-
ro con costos elevados en su implementación por parte del desarrollador. Al final
y sin ser lo último, el producto resultante del diseñador será un conjunto de imá-
genes o un esquema que mostrará lo pretendido de manera visual para la aplica-
ción de software, y le deja al desarrollador la tarea de volver a armar esto dentro
de las líneas de código, quien no lo conseguirá con exactitud al compararlo con
lo propuesto en un principio por el diseñador.
Y es aquí donde han surgido herramientas que traducen, de alguna forma, esto
que el diseñador piensa y plasma en algo que el desarrollador pueda usar. Así, es
posible encontrar herramientas muy potentes como Adobe Fireworks donde,
por medio del modelo visual creado por el diseñador, el desarrollador obtiene un
conjunto de imágenes y código HTML. A pesar de eso, este tipo de herramientas
acarrea un problema, ya que se enfocan en el diseñador y no en el desarrollador,
creando código HTML que, basado en el dibujo propuesto, generan HTML poco
útil para su implementación, como podemos ver a continuación. El siguiente es
el resultado HTML generado para la Figura 2.
tr
tdimg src=”images/spacer.gif” width=”103” height=”1” border=”0”alt=””
//td
2. MICROSOFT EXPRESSION BLEND 2
32
02_Silverlight.qxp 9/30/09 1:23 PM Page 32
td
[...41 líneas eliminadas ...]
td colspan=”2”img name=”Untitled1_r4_c1” src=”images/Untitled-
1_r4_c1.gif”
width=”112” height=”60” border=”0” id=”Untitled1_r4_c1” alt=”” //td
tdimg src=”images/spacer.gif” width=”1” height=”60” border=”0” alt=””
//td
/tr
Y, si bien este código puede ayudar, resulta imposible de usar para el desarrollador,
por lo que éste se verá forzado a reescribir partes o su totalidad para poder obtener
código que le sea útil. Para esto utilizará sólo código HTML, debido a que a éste se
le pueden agregar cuestiones programáticas a diferencia del anterior.
spanFiltro de búsqueda/span
br
select
option/option
option/option
option/option
/select
Figura 2. A la derecha podemos
ver lo que consiguió el desarrollador como resultado
del concepto ideado por el diseñador.
Un paseo por Expression Blend 2
33
02_Silverlight.qxp 9/30/09 1:23 PM Page 33
El problema es claro: estas herramientas hacen las veces de traductores, pero no de ge-
neradores. Traducen lo que el diseñador quiso decir a algo que el desarrollador pueda
entender, pero, en este proceso de traducción, las herramientas no traducen funciona-
lidad, por lo que el desarrollador no la obtendrá y deberá retraducirla por su cuenta.
La diferencia sustancial sobre este concepto por parte de Expression Blend 2 reside en
que no es un traductor, sino un generador de funcionalidad, con la característica
de que para el diseñador la herramienta se comportará como cualquier otra herra-
mienta de las que está acostumbrado a usar. Sin embargo, a medida que diagrama y
diseña los contenidos visuales, ésta generará funcionalidad lista para ser implementa-
da por el desarrollador de software, como podemos observar en el siguiente código:
Grid x:Name=”LayoutRoot” Background=”White”
TextBlock Height=”23” HorizontalAlignment=”Left” Margin=”96,32,0,0”
VerticalAlignment=”Top” Width=”174” Text=”Filtro de búsqueda”
TextWrapping=”Wrap” FontFamily=”Aharoni” FontSize=”18”/
ComboBox Height=”42” HorizontalAlignment=”Left” Margin=”96,59,0,0”
Style=”{StaticResource ComboBoxStyle1}” VerticalAlignment=”Top”
Width=”160” OpacityMask=”{x:Null}”
ComboBox.Foreground
LinearGradientBrush EndPoint=”0.5,1”
StartPoint=”0.5,0”
GradientStop Color=”#FFF36767”/
GradientStop Color=”#FFFFFFFF” Offset=”1”/
/LinearGradientBrush
/ComboBox.Foreground
ComboBox.Background
LinearGradientBrush EndPoint=”0.5,1”
StartPoint=”0.5,0”
GradientStop Color=”#FFC07070”/
GradientStop Color=”#FF0F0000” Offset=”1”/
/LinearGradientBrush
2. MICROSOFT EXPRESSION BLEND 2
34
_`
Existen especializaciones en el desarrollo de software que se enfocan en la optimización de las
interfaces visuales, llegando al punto de calcular la cantidad de clics que deberá hacer un usuario
para conseguir realizar una acción determinada. La implementación de estas técnicas produce
mayor aceptación de los productos por parte de los usuarios.
OPTIMIZACIÓN DE LA INTERFAZ
02_Silverlight.qxp 9/30/09 1:23 PM Page 34
/ComboBox.Background
/ComboBox
/Grid
El diseñador verá, en lugar del código anterior, un modelo como el que se mues-
tra en la figura que aparece a continuación:
Figura 3. Una lista desplegable creada con Expression Blend 2,
que generará código XAML listo para ser usado por el desarrollador.
Como el desarrollador obtiene código que se adapta a sus necesidades, puede en-
focarse directamente en la solución del problema. A modo de ejemplo, en las si-
guientes líneas de código vemos cómo el desarrollador agrega algunas líneas de
código C# en la clase asociada al código XAML para generar funcionalidad so-
bre el producto del diseñador:
public partial class Page : UserControl
{
public Page()
{
// Required to initialize variables
InitializeComponent();
this.ComboBox.Items.Add(“Item 1”);
this.ComboBox.Items.Add(“Item 2”);
Un paseo por Expression Blend 2
35
02_Silverlight.qxp 9/30/09 1:23 PM Page 35
this.ComboBox.Items.Add(“Item 3”);
}
}
El resultado de esta implementación de código podemos verlo a continuación:
Figura 4. Como observamos en esta imagen, el resultado propuesto
por el diseñador y la implementación del desarrollador son idénticas.
Microsoft Expression Blend 2, entonces, sirve de nexo entre los dos elementos
involucrados en el desarrollo, tanto para diseñadores como para desarrolladores.
De esta manera se logra que los productos resultantes en ambos casos sean com-
patibles entre sí, para que ninguno de los profesionales involucrados tenga la ne-
cesidad de salir de su ámbito natural de trabajo. El resultado final será, entonces,
que el diseñador obtendrá en la pieza de software el comportamiento y la apariencia
visual, tal como los había ideado, mientras que el desarrollador no se verá forzado
a intentar traducir estas ideas a elementos programáticos y se dedicará exclusiva-
mente a la funcionalidad y a la resolución del problema.
2. MICROSOFT EXPRESSION BLEND 2
36
RRR
Contar con un diseño visual de la aplicación de manera temprana no sólo sincronizará a los
miembros del equipo de desarrollo, ya que todos tendrán una idea general del producto final, sino
que puede servir de disparador de retroalimentación por parte del cliente al ver con antelación
la idea del producto terminado.
PROTOTIPO DEL PRODUCTO
02_Silverlight.qxp 9/30/09 1:23 PM Page 36
Un recorrido por Expression Blend 2
Al iniciar Expression Blend 2 o al crear un nuevo proyecto con él, podemos elegir
entre cuatro tipos diferentes. Tenemos dos proyectos específicos para Silverlight y
sus diferentes versiones, pero también podemos diseñar y trabajar con proyectos
Windows Presentation Foundation (WPF).
• Aplicación WPF: este tipo de proyecto representa una aplicación de escritorio con
soporte para WPF. Si tenemos en cuenta que WPF también se compone de código
XAML, es posible crear un entorno visual directamente desde Expression Blend 2.
• Librería de controles WPF: esta librería de controles está especializada en el en-
capsulamiento de elementos XAML y código de programación para su posterior
reutilización en aplicaciones WPF. Debemos optar por esta opción cuando quere-
mos crear elementos reutilizables para ser incorporados en distintas aplicaciones.
• Sitio de Silverlight 1: este tipo de proyectos está orientado a crear sitios web con
soporte para la versión 1 de Silverlight. Debemos tener en cuenta que este modelo
no es tratado en este libro y además representa una versión antigua del software.
• Aplicación de Silverlight 2: una vez instalado el Service Pack 1 para Expression
Blend 2, podremos ver esta clase de trabajos. Éste es el tipo de proyectos sobre los
cuales nos moveremos, tanto de manera visual como programática.
Figura 5. Lista de proyectos incluidos en Expression Blend 2.
Un paseo por Expression Blend 2
37
,
La mayoría de los controles preestablecidos en Silverlight presentarán un comportamiento si-
milar al de sus homónimos presentes en el desarrollo web y de escritorio. Al interactuar con
ellos se deberá, por consiguiente, imitar las mismas líneas de código usadas en los demás
ambientes de desarrollo con Microsoft .Net.
CONTROLES EN SILVERLIGHT
02_Silverlight.qxp 9/30/09 1:23 PM Page 37
Además de poder indicar el nombre del proyecto que vamos a crear y la ubica-
ción física que tendrá, es posible seleccionar el lenguaje de programación con el
cual preferimos trabajar. Vale aclarar que, para poder conseguir esta lista, es ne-
cesario haber instalado esos lenguajes en nuestra estación de trabajo. El hecho de
poder seleccionar un lenguaje de programación se refiere a que cualquier código
que se realice desde Expression Blend 2 se hará en ese lenguaje, por lo que es im-
portante elegir aquel con el que estemos más familiarizados.
Explorador de soluciones
Una vez que hemos creado el proyecto Silverlight 2, podremos navegar entre sus
archivos desde el explorador de la solución, que típicamente puede ser encontrado
a la derecha de la aplicación, como podemos observar en la Figura 6. Este explorador
nos mostrará, como elementos iniciales, una página del tipo XAML más una clase
creada en el lenguaje seleccionado, en este caso C#. Esta clase de C# es la que será
usada para generar el código que maneje los elementos creados en la página XAML.
Figura 6. El explorador de soluciones (área superior derecha)
de Expression Blend 2 con los elementos iniciales de una aplicación Silverlight 2.
2. MICROSOFT EXPRESSION BLEND 2
38
RRR
Para mejorar nuestro desarrollo en Expression Blend 2, es recomendable tener instalado, ade-
más, alguna de las herramientas de desarrollo de software de Microsoft, como por ejemplo
Visual Studio 2008. Esto hará que, de tener que agregar código de programación a nuestro pro-
yecto Silverlight, lo podamos hacer con mayor facilidad desde estas herramientas.
INTEROPERABILIDAD
02_Silverlight.qxp 9/30/09 1:23 PM Page 38
Página inicial de Silverlight 2
El archivo Page.xaml es considerado la página o componente de inicio para nuestra
aplicación Silverlight 2, teniendo como contenido el siguiente código:
UserControl
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
x:Class=”SilverlightApplication2.Page”
Width=”640” Height=”480”
Grid x:Name=”LayoutRoot” Background=”White”/
/UserControl
En el caso de Silverlight 2, el elemento inicial es representado por un tag llamado
UserControl. Lo que nos dice esto es que no será considerado como una apli-
cación en sí misma, sino como un componente que puede ser incrustado o con-
sumido por otras aplicaciones del tipo Silverlight, así como por aplicaciones web.
En la misma declaración de atributos de este control Silverlight, se incluye el
nombre de la clase de C# encargada de manejar los componentes del control, así
como el ancho y el alto, en pixeles, del control. Si exploramos el contenido de
esa clase, podremos ver lo siguiente:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
Un paseo por Expression Blend 2
39
RRR
Es posible hacer que nuestro control Silverlight se adapte a la superficie que lo contiene. Si co-
locamos el elemento Silverlight dentro de una tabla HTML y configuramos las propiedades del
elemento para que sus atributos Width y Height sean igual a Auto, éste se adaptará de manera
automática a las dimensiones de su contenedor.
DIMENSIONES DE SILVERLIGHT
02_Silverlight.qxp 9/30/09 1:23 PM Page 39
using System.Windows.Shapes;
namespace SilverlightApplication2
{
public partial class Page : UserControl
{
public Page()
{
// Required to initialize variables
InitializeComponent();
}
}
}
Esta clase, como ya comentamos, es la que será usada como contenedor de la
implementación del código que interactuará con los componentes colocados en la
página XAML previamente vista. Esto quiere decir que, si queremos que nuestra
aplicación Silverlight consuma datos de una base de datos o reaccione apoyada en
estímulos por parte del usuario, deberíamos escribir esas líneas dentro de esta clase.
Por supuesto, no estamos obligados a acumular todas las líneas de código en este
único archivo ya que, como en todo lenguaje orientado a objetos, podremos crear
tantas clases como necesitemos sin estar obligados a tener una página XAML por
cada una. Así, podríamos encapsular la lógica de negocios o el acceso a datos en
clases especializadas, y generar código mantenible y fácilmente modificable.
La página App.xaml
La página App.xaml, junto con la clase de código que la representa, es otro de los
archivos creados inicialmente. Esta clase es usada en especial para almacenar có-
digo XAML, que en el caso de App.xaml puede ser reusado dentro de todas las
demás páginas de tipo XAML. Como podemos ver en el siguiente código:
2. MICROSOFT EXPRESSION BLEND 2
40
,
Como una buena práctica en el desarrollo de software, encontramos los patrones de diseño de
software. Éstos representan formas de crear código para solucionar problemas específicos. Es
importante tener presente estos patrones para mejorar la calidad del código creado en Silverlight.
Como resultado, obtendremos código más prolijo y más fácil de modificar.
PATRONES DE DISEÑO DE SOFTWARE
02_Silverlight.qxp 9/30/09 1:23 PM Page 40
Application.Resources
!— Resources scoped at the Application level should be defined here.
—
Style x:Key=”TextBoxStyle1” TargetType=”TextBox”
Setter Property=”BorderThickness” Value=”1”/
Setter Property=”Background”
Setter.Value
LinearGradientBrush EndPoint=”0.5,1”
StartPoint=”0.5,0”
GradientStop Color=”#FFE8EFF1”/
GradientStop Color=”#FF87DFF4” Offset=”1”/
/LinearGradientBrush
/Setter.Value
/Setter
Setter Property=”Foreground” Value=”#FFFF0000”/
Setter Property=”Padding” Value=”2”/
Setter Property=”BorderBrush”
...
...
En el código anterior, el archivo App.xaml es usado para alojar la definición de un
nuevo elemento TextBox, que presenta ciertas particularidades de sus atributos de
color y comportamiento, como podemos ver en la Figura 7. Este nuevo elemento,
ahora, puede ser accedido y consumido por cualquier otro TextBox que se en-
cuentre dentro de nuestra aplicación. Por lo común, cuando desarrollemos con
Silverlight, tendremos la necesidad de crear nuestros propios esquemas visuales
para que sean aplicados sobre controles específicos. Una forma de compartir estos
esquemas es mediante su colocación dentro de este archivo. De cualquier manera,
hablaremos más de estos esquemas y propiedades en los capítulos 4 y 5.
Un paseo por Expression Blend 2
41
RRR
Debemos tener cuidado en la cantidad de información que agregamos a nuestros archivos XAML,
ya que éstos deben ser descargados por el usuario. Un archivo de gran tamaño tomará más
tiempo en ser descargado, en detrimento de la experiencia del usuario. Podemos usar carga por
demanda para mejorar esta experiencia.
TAMAÑO DE ARCHIVOS
02_Silverlight.qxp 9/30/09 1:23 PM Page 41
Figura 7. El esquema generado puede ser aplicado a otros
controles del mismo tipo en cualquier otra página de Silverlight.
Con respecto a la página de código (App.xaml.cs), podemos decir que presenta
un conjunto de eventos que se dispararán en determinados momentos de la vi-
da de nuestra aplicación. El código genérico se muestra a continuación, y luego
lo analizaremos con más detalle:
public App()
{
this.Startup += this.OnStartup;
this.Exit += this.OnExit;
this.UnhandledException += this.Application_UnhandledException;
InitializeComponent();
}
private void OnStartup(object sender, StartupEventArgs e)
{
// Load the main control here
this.RootVisual = new Page();
}
private void OnExit(object sender, EventArgs e)
{
}
2. MICROSOFT EXPRESSION BLEND 2
42
02_Silverlight.qxp 9/30/09 1:23 PM Page 42
El primer método, constructor de esta clase, se encarga de enlazar eventos inhe-
rentes al comportamiento de nuestra aplicación. El método OnStartup se ejecutará
al inicio de la aplicación, en este caso, podríamos colocar código en él para con-
seguir algún comportamiento necesario al momento de inicializarse nuestra apli-
cación. Por ejemplo, podríamos necesitar inicializar objetos o conectarnos a un
servicio web, entre otras posibilidades. En el mismo caso, el evento OnExit será dis-
parado en el momento en el que la aplicación sea cerrada o terminada, y de igual
forma que en el caso anterior, podríamos necesitar liberar ciertos recursos o realizar
acciones específicas cuando la aplicación concluya.
El entorno de Expression Blend 2
El entorno de Expression Blend 2 no se limita a los archivos previamente tratados.
Si tenemos en cuenta que esta herramienta puede ser usada tanto por diseñadores
como por desarrolladores, podremos encontrar elementos útiles para los dos casos.
Una de las secciones destacadas involucra el lienzo de dibujo central. En este lien-
zo, podremos arrojar y ordenar todos los controles incluidos en Silverlight, así co-
mo crear nuestros propios modelos y controles.
Figura 8. En este lienzo, podemos ver cómo
son manipulados distintos controles de manera visual.
Desde esta área central, también es posible interactuar en forma directa con el
código XAML. En nuestra interfaz podemos ver, en la parte superior derecha, las
opciones para intercambiar entre los diferentes modos de visualización: Diseño,
XAML o Dividir (mixto), y tenemos la posibilidad de modificar los componentes
desde cualquiera de estas vistas. Si contamos con cierta experiencia en edición de
Un paseo por Expression Blend 2
43
02_Silverlight.qxp 9/30/09 1:23 PM Page 43
XAML, es probable que trabajemos en el modo mixto o de pantalla dividida, ya
que esto puede acelerar nuestro trabajo de manera significativa.
El próximo grupo de paneles que vamos a inspeccionar es el de las propiedades.
Éste se encuentra situado a la derecha de Expression Blend 2. Típicamente, estas
propiedades son el acceso rápido a las configuraciones de aspecto y comportamiento
de los controles adicionados al lienzo de edición. Para lograr la inspección de las
propiedades de un control, primero será necesario seleccionarlo. Según el control
seleccionado, las propiedades se verán afectadas en relación a éste por lo que no con-
taremos con las mismas opciones en todos los casos.
Figura 9. Existen otras propiedades relacionadas con diferentes controles,
sólo debemos movernos usando la barra de desplazamiento ubicada a la derecha.
En esta área también podemos encontrar, en la parte superior, opciones que tengan
que ver con el proyecto. En especial, la pestaña relacionada con los recursos de
la aplicación, donde se listarán todos los atributos previamente configurados,
como los alojados en el archivo App.xaml, que ya hemos tratado. La gran venta-
ja de esta lista de recursos radica en que podemos arrastrar cualquiera de estos
2. MICROSOFT EXPRESSION BLEND 2
44
RRR
En Silverlight, no sólo es posible modificar la apariencia visual de los controles nativos mediante
la generación de esquemas. También podremos crear nuestros propios componentes y controles
heredándolos en nuestro propio código y creando nueva lógica funcional.
IMPLEMENTACIÓN DE CONTROLES
02_Silverlight.qxp 9/30/09 1:23 PM Page 44
elementos sobre alguno de los controles existentes para aplicar las configuracio-
nes a ese control. El resultado de arrastrar el estilo configurado al inicio permite
obtener lo que podemos ver en la siguiente figura.
Figura 10. El control de caja de texto posee, una vez aplicado, el estilo
definido en el elemento TextBoxStyle1, que aparece debajo de la pestaña de recursos.
El último panel que agrupa información sobre nuestra aplicación Silverlight se en-
cuentra a la izquierda del lienzo de dibujo. Sobre estos grupos, en la parte superior, se
ubican las transformaciones y animaciones de los componentes de nuestra aplica-
ción. Aunque hablaremos de estas propiedades con mayor detalle en el capítulo 5, vale
recalcar que se pueden generar diferentes efectos de movimiento y transformaciones
desde esta sección. Debajo de este panel, se encuentra el árbol de controles de la pá-
gina que estamos visualizando. Los controles se agruparán de manera jerárquica sobre
la base del contenedor inmediato superior. Si tenemos en cuenta que los controles
XAML pueden ser contenedores de otros controles XAML, esta estructura nos dará
rápido acceso a cada uno de los elementos que componen un control de manera rápi-
da. En la Figura 11, podemos ver un ejemplo de este árbol y del panel de animaciones.
Un paseo por Expression Blend 2
45
_`
Todas las imágenes, videos y sonidos que agreguemos a nuestro proyecto, así como cualquier
archivo externo, serán comprimidos en un único archivo final con extensión XAP. Este archivo
es, en realidad, un archivo zip que contiene todos los elementos creados por el proyecto Silverlight.
COMPRESIÓN DE ARCHIVOS
02_Silverlight.qxp 9/30/09 1:23 PM Page 45
Figura 11. En este árbol de controles se muestra la lista
de elementos agregados antes a nuestro lienzo de dibujo, cómo éstos
son contenidos por una grilla y ésta, a su vez, por el control Silverlight.
La barra de herramientas
Desde la barra de herramientas de Expression Blend 2, tendremos acceso a todos
los controles y componentes preestablecidos de Silverlight y de Microsoft .Net
Framework. Podemos separar la lista de controles en los siguientes grupos:
• Elementos de dibujo: son aquellos que nos dan acceso a herramientas de dibujo
vectoriales. Con éstos, podremos dibujar líneas, curvas, círculos y rectángulos.
Figura 12. Listas de controles para dibujo vectorial.
• Contenedores y agrupadores: la tarea de estos elementos consiste, principal-
mente, en agrupar otros controles Silverlight, aunque también se encargan de
ordenar, dentro de la superficie de dibujo, la disposición de esos elementos. Así,
2. MICROSOFT EXPRESSION BLEND 2
46
02_Silverlight.qxp 9/30/09 1:23 PM Page 46
podemos encontrar grillas, donde se definirán filas y columnas (agregando den-
tro de cada celda distintos controles y componentes) o elementos de barras de
desplazamiento para colocar contenido que exceda los límites de ancho o alto de-
finidos para una zona de nuestra aplicación.
Figura 13. Controles para la agrupación y contención de otros elementos y controles.
• Interacción con el usuario: este último grupo representa aquellos controles y
componentes que sirven para capturar comportamiento por parte del usuario.
Dentro de los más conocidos, podemos encontrar los botones, cajas de texto, lis-
tas desplegables y botones de selección múltiple, entre otros.
Figura 14. Controles más comunes para capturar información por parte del usuario.
Los controles antes nombrados suelen ser los que se usan con mayor frecuencia para el
desarrollo de aplicaciones con Silverlight, pero existen otros que no se ven de forma di-
recta. Para poder acceder a ellos, es necesario seleccionar el último elemento de la lista
en la barra de herramientas. Al hacerlo, podremos ver la lista completa de controles dis-
ponibles y agregarlos a nuestra colección de controles, como se muestra a continuación.
Un paseo por Expression Blend 2
47
02_Silverlight.qxp 9/30/09 1:23 PM Page 47
Figura 15. Todos los controles disponibles desde Expression Blend 2.
Crear nuestra primera aplicación con Expression Blend 2
Ya estamos en condiciones de comenzar a trabajar con Expression Blend 2 para crear
nuestra primera aplicación Silverlight. En este caso, crearemos un visor simple de
videos. Este visor deberá contemplar las posibilidades de iniciar, pausar y detener, en
forma completa, una película designada por nosotros. El primer paso es crear una
nueva aplicación Silverlight 2. Una vez hecho esto, necesitaremos agregar a nuestro
lienzo de dibujo un control del tipo MediaElement, que sirve para representar videos,
imágenes y sonidos en Silverlight. Para poder agregar este control, es necesario que lo
busquemos en la lista completa de controles Silverlight, como vimos en la Figura 15,
ya que no se encuentra disponible en la barra de herramientas. Junto con este control,
agregaremos alguno del tipo Border. Este control es necesario para darle una apa-
riencia de caja a nuestra película, debido aque el control MediaElement no posee
características. Podemos obtener un cambio en la configuración visual del control
Border si modificamos sus características en la pestaña Propiedades. Para este caso,
2. MICROSOFT EXPRESSION BLEND 2
48
_`
A medida que Silverlight va madurando, más empresas y portales en la Web se inclinan por
la utilización de esta tecnología sobre otras. Uno de los últimos portales que optó por modi-
ficar toda su implementación de servicios para los usuarios fue Terra, al cambiar su utilización
de Adobe Flash por Silverlight.
CADA VEZ MÁS SE INCLINAN POR SILVERLIGHT
02_Silverlight.qxp 9/30/09 1:23 PM Page 48
debemos modificar las propiedades del fondo (Background), para que se aplique el
color degradado, y las de apariencia, colocando el grosor del borde del control
(BorderThikness) en 1 y el radio de curvatura de las esquinas (CornerRadius) en 10.
Figura 16. Propiedades aplicadas al control Border.
Por último, el control MediaElement debe ser contenido por el control que representa
el borde configurado previamente. Para esto, arrastramos el control MediaElement den-
tro del control Border para lograr el efecto deseado. Como podemos editar directamente
XAML, es posible lograr el mismo fin con las siguientes líneas de código:
Border Margin=”95.5,57,91.5,217” BorderBrush=”#FF000000”
BorderThickness=”1,1,1,1” CornerRadius=”10,10,10,10”
Border.Background
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF6985B5”/
GradientStop Color=”#FFFFFFFF” Offset=”1”/
/LinearGradientBrush
/Border.Background
MediaElement Height=”Auto” Width=”Auto” OpacityMask=”{x:Null}”/
/Border
Por último, es necesario que agreguemos tres botones para las tres acciones antes
definidas. Podremos cambiarle el texto que se va a mostrar en cada botón, presio-
nando dos veces con el puntero del ratón sobre el control, o mediante sus propie-
dades. El resultado debería ser similar al mostrado en la siguiente figura.
Un paseo por Expression Blend 2
49
02_Silverlight.qxp 9/30/09 1:23 PM Page 49
Figura 17. Nuestro visor de videos con los botones que controlarán la reproducción.
Una vez conseguido el visor de videos, es necesario configurar el control MediaElement
para especificarle cuál será el video que se va a reproducir. Seleccionamos el con-
trol MediaElement en la lista de propiedades y buscamos la fuente de contenido
(Source). Por lo general, podremos seleccionar formatos soportados por Silverlight
de los que hablaremos con más detalles en el capítulo 6 cuando veamos el compo-
nente MediaElement de manera especial. Una vez que hemos seleccionado el video
en cuestión, presionamos la tecla F5 para inicializar la aplicación. Esta acción de-
berá iniciar un explorador de Internet y desplegar la aplicación creada. Podremos
notar que el video se reproduce con normalidad, pero los botones creados para ca-
da una de las acciones no funcionan como esperábamos, debido a que no hemos
generado ningún código que las realice (Figura 18).
Para conseguirlo, el primer paso es asignarle un nombre a nuestro MediaElement,
ya que sin él no podremos acceder a las propiedades del control, por lo que no se-
rá posible iniciarlo, pausarlo o detenerlo. Podemos asignarle el nombre al control
seleccionándolo y agregándole el mismo que tiene en la lista de propiedades o me-
diante XAML por medio del atributo x:Name=”Nombre del Control”. El elemento
MediaElement quedará como se ve en el siguiente código:
2. MICROSOFT EXPRESSION BLEND 2
50
RRR
Si necesitamos buscar material sobre desarrollo de interfaces visuales, es posible que también
las encontremos mediante la sigla UX (User eXperience o experiencia de usuario, por su signifi-
cado en inglés). Debido a que el término, con el tiempo, mutó, tendremos más chances de hallar
información mediante este último nombre.
INTERFACES DE USUARIO
02_Silverlight.qxp 9/30/09 1:23 PM Page 50
MediaElement Height=”Auto” Width=”Auto” Source=”silverlight.wmv”
AutoPlay=”False” x:Name=”visorVideo”/
Figura 18. El visor de videos trabajando de manera correcta en nuestro navegador.
Si tenemos en cuenta que la lógica debe ser creada en la clase de código C#, necesita-
remos escribir algunas líneas en ella para realizar las acciones propuestas por los tres
botones. Tenemos varios caminos para lograrlo: podríamos usar Visual Studio 2008
para generar el código. Visual Studio 2008 es una herramienta de alto nivel para la
creación de código para aplicaciones, así como para realizar pruebas sobre él. Por otro
lado, sería posible modificar el archivo de clase y el código XAML por nuestra cuen-
ta. Sin embargo, esto puede redundar en un aumento de trabajo y del tiempo de
desarrollo y crear posibles problemas en la confección del código, si no somos expe-
rimentados conocedores del lenguaje de programación utilizado. De cualquier ma-
nera, para este ejemplo, si optamos por la segunda opción, sólo deberemos seguir unos
cuantos pasos. Primero, en el código XAML, tendremos que agregar el atributo
Click=”Nombre del Método” por cada botón creado. Click representa el evento por el
Un paseo por Expression Blend 2
51
RRR
Expression Blend 2 trae consigo un pequeño servidor de páginas web. Este servidor es activado
en el momento en que queremos depurar nuestro trabajo y ver los resultados obtenidos. Gra-
cias a este servidor, no dependeremos de grandes infraestructuras para desplegar y ejecutar
nuestros proyectos cada vez que necesitemos validar lo que estemos desarrollando.
SERVIDOR WEB
02_Silverlight.qxp 9/30/09 1:23 PM Page 51
cual se disparará la acción o la lógica contenida en el método o función creada en el
código C#. Así, cuando el usuario presione el botón en cuestión, el evento Click será
disparado y se desencadenará toda la lógica que hayamos programado. Es necesario,
entonces, que modifiquemos nuestro XAML para agregar los tres eventos:
Button Height=”33” HorizontalAlignment=”Left” Margin=”95.5,0,0,162”
VerticalAlignment=”Bottom” Width=”76.5” Content=”Iniciar”
RenderTransformOrigin=”0.481,0.515” Click=”Iniciar”/
Button Height=”33” HorizontalAlignment=”Left” Margin=”193,0,0,162”
VerticalAlignment=”Bottom” Width=”76.5”
RenderTransformOrigin=”0.481,0.515” Content=”Pausar” Click=”Pausar”/
Button Height=”33” Margin=”287,0,276,162” VerticalAlignment=”Bottom”
Width=”76.5” RenderTransformOrigin=”0.5,0.5” Content=”Detener”
Click=”Detener”/
Estos tres eventos ahora hacen referencia a tres funciones: Iniciar, Pausar y Detener. Pa-
ra agregar la lógica que maneje estas acciones, necesitamos modificar nuestra clase C#.
Si no contamos con Visual Studio 2008, podremos abrirla con el bloc de notas o cual-
quier editor de texto. El resultado final debería ser como el que sigue:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightApplication2
{
public partial class Page : UserControl
{
public Page()
{
2. MICROSOFT EXPRESSION BLEND 2
52
02_Silverlight.qxp 9/30/09 1:23 PM Page 52
// Required to initialize variables
InitializeComponent();
}
private void Iniciar(object sender, RoutedEventArgs e)
{
visorVideo.Play();
}
private void Pausar(object sender, RoutedEventArgs e)
{
visorVideo.Pause();
}
private void Detener(object sender, RoutedEventArgs e)
{
visorVideo.Stop();
}
}
}
En el código anterior, vemos cómo una simple línea de código por acción pue-
de ejecutar, pausar o detener el video. Si volvemos a ejecutar nuestra aplicación
Silverlight, deberemos poder interactuar con el video seleccionado mediante los
botones, iniciándolo, deteniéndolo y pausándolo.
Un paseo por Expression Blend 2
53
… RESUMEN
Expression Blend 2 es una herramienta altamente flexible que une dos áreas del desarrollo
de software que habían estado separadas y con falta de comunicación. De esta forma les da
tanto a los diseñadores como a los desarrolladores una forma de comunicarse para que los
primeros puedan ver plasmadas sus ideas en las aplicaciones tal cual las han concebido, y los
desarrolladores implementen estas ideas sin la necesidad de reescribir código, para no
invertir tiempo y esfuerzo de manera innecesaria.
02_Silverlight.qxp 9/30/09 1:23 PM Page 53
54

PREGUNTAS TEÓRICAS
1 ¿Cuál es, en el desarrollo web, el principal
problema con el que se encuentra un desa-
rrollador al recibir el trabajo del diseñador
para ser implementado?
2 ¿Por qué es importante poner esfuerzo en
el área de experiencia visual del usuario?
3 ¿Qué herramientas intentan unir el diseño
y el desarrollo de software?
4 ¿Por qué es importante la creación de proto-
tipos visuales en el desarrollo de software?
5 ¿Podemos encontrar todos los controles y
componentes HTML representados en Sil-
verlight con XAML?
6 ¿Qué tipos de proyectos es posible crear
con Expression Blend 2?
7 ¿Es necesario instalar algún programa adi-
cional para poder desarrollar aplicaciones
Silverlight 2 con Expression Blend 2?
8 Si queremos ver todos los controles de Ex-
pression Blend 2, ¿cómo accedemos a ellos?
9 ¿Es necesario contar con un servidor web
para depurar las aplicaciones Silverlight
desde Expression Blend 2?
10 ¿Cuántos tipos de controles encontramos en
Silverlight? ¿Cómo los categorizamos?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Ingrese y navegue por Quince (http://
quince.infragistics.com), el sitio web de
Infragistics dedicado a la mejora de las in-
terfaces visuales.
2 Diríjase al sitio web oficial de Silverlight
(http://silverlight.net) para ver más ejem-
plos sobre esta plataforma.
3 Intente crear un visor de videos por Inter-
net, ejecutando la aplicación creada me-
diante el uso de IIS (Internet Information
Services).
4 Ingrese en www.microsoft.com/surface,
el sitio web de Microsoft Surface, para ver
buenos ejemplos de interfaces visuales y
su aplicación en soluciones de software.
5 Visite el sitio de experiencia para el usua-
rio de Microsoft (www.microsoft.com/
design) para maximizar el conocimiento
sobre posibilidades involucradas en esta
área de la ingeniería de software.
02_Silverlight.qxp 9/30/09 1:23 PM Page 54
El mejor trabajo,
con la mejor
herramienta
Silverlight para desarrolladores 56
Puesta a punto de Visual
Studio 2008 56
Silverlight 2 con Visual Studio 59
Crear la primera aplicación
con Visual Studio 2008 63
Interoperabilidad con
Expression Blend 2 76
Resumen 79
Actividades 80
Capítulo 3
Más allá de nuestro conocimiento,
la forma más eficiente de crear viene
de la mano de la mejor herramienta
disponible. Así como los diseñadores
visuales tienen una herramienta creada
para ellos, los desarrolladores
no se pueden quedar atrás. Visual Studio
2008 y Silverlight son una mezcla
con la que podremos obtener código
de extrema calidad.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
03_Silverlight.qxp 9/30/09 1:29 PM Page 55
SILVERLIGHT PARA DESARROLLADORES
En este punto, ya hemos pasado por los conceptos iniciales de Silverlight y recorri-
mos un poco una de las herramientas provistas por Microsoft, Expression Blend 2,
para desarrollar aplicaciones para esta plataforma. En este capítulo, hablaremos de
Visual Studio 2008 como la herramienta ideal para los desarrolladores de software
y también para desarrollar aplicaciones Silverlight. Además, crearemos una nueva
aplicación que consuma datos y se los mostraremos al usuario.
Puesta a punto de Visual Studio 2008
En el primer capítulo, comentamos que la versión 2 de Silverlight no viene incluida
en Visual Studio 2008 y, por consiguiente, es necesario que hagamos esta instala-
ción descargando los componentes desde la página de Microsoft. El motivo de es-
ta sección en este capítulo se debe a que, en muchas ocasiones, nos encontramos
con el dilema de no saber qué versión, componente u herramienta descargar. En
general, los sitios de los proveedores suelen presentarnos más de una versión dis-
ponible para su descarga, pero si elegimos una incorrecta nos retrasará en nuestro
trabajo, así como también podemos encontrarnos con algún funcionamiento ines-
perado mientras realizamos nuestro trabajo. En la Figura 1, se ilustra el sitio web de
Microsoft que representa el portal de entrada para Silverlight.
Figura 1. Portal de Silverlight en Microsoft.com.
En esta figura, se muestra una lista de componentes que pueden ser descargados.
El primero hace referencia al motor o plugin de Silverlight. Este motor es el que
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
56
03_Silverlight.qxp 9/30/09 1:29 PM Page 56
debe instalar todo usuario que quiera ver las aplicaciones Silverlight desde el na-
vegador. Por supuesto, no es necesario que proveamos por nuestra cuenta este
plugin ni que tengamos que instalarlo de forma manual en cada uno de los equi-
pos y de los navegadores que quieran nuestro producto ya que, en la declaración
del objeto Silverlight en el código HTML, se incluye una comprobación de ver-
siones, además de indicarle al navegador de dónde obtener esta versión:
object data=”data:application/x-silverlight,” type=”application/x-
silverlight-2” width=”100%” height=”100%”
param name=”source” value=”SilverlightApplication1.xap”/
param name=”onerror” value=”onSilverlightError” /
param name=”background” value=”white” /
param name=”minRuntimeVersion” value=”2.0.31005.0” /
param name=”autoUpgrade” value=”true” /
a href=”http://go.microsoft.com/fwlink/?LinkID=124807” style=”text-
decoration: none;”
img src=”http://go.microsoft.com/fwlink/?LinkId=108181”
alt=”Get Microsoft Silverlight” style=”border-style: none”/
/a
/object
Este código es el que deberemos usar de manera habitual para la incrustación de
aplicaciones Silverlight en páginas webs. Si analizamos las partes del código, ve-
mos que, dentro del atributo data, se detalla el tipo de componente por ejecutar.
De esta forma, el navegador sabrá que el objeto requerido es del tipo Silverlight.
El atributo type específica la versión de aplicación que se usará, en nuestro caso,
Silverlight 2. Los elementos param, con sus atributos name, preconfiguran la aplica-
ción Silverlight. La propiedad onerror especifica el nombre de la función JavaScript
que se ejecutará si ocurriera un error en el transcurso del implemento de la apli-
cación. Por su parte, minRuntimeVersion detalla la versión exacta de la aplicación,
por lo que deberemos tener el plugin compatible para poder ejecutarla.
Silverlight para desarrolladores
57
,
Este software no es un componente para realizar presentaciones vistosas en Internet. Por el con-
trario, Silverlight no sólo cumple con esta característica, sino que extiende el desarrollo de apli-
caciones profesionales al ambiente web con contenido dinámico. Podemos usar Silverlight, en
especial, cuando tengamos que resolver problemas complejos desde la Web.
¿QUÉ ES SILVERLIGHT EN REALIDAD?
03_Silverlight.qxp 9/30/09 1:29 PM Page 57
El parámetro autoUpgrade representa la capacidad del navegador para descargar en
forma automática alguna nueva versión detectada, previa autorización del usuario.
Por último, si el navegador no cuenta con la versión indicada o simplemente no tie-
ne el plugin instalado, la página mostrará la imagen de la figura siguiente, con un
vínculo a la versión descargable del plugin.
Figura 2. Al no tener el plugin instalado, el usuario
verá la imagen que le sugiere descargar el complemento.
El segundo elemento de la lista de la Figura 1 representa todas las herramientas y
SDKs (Software Development Kits o, en castellano, Grupo de herramientas para
desarrollo). Necesitaremos descargar e instalar este conjunto de herramientas só-
lo si ya contamos con las plantillas y actualizaciones de Visual Studio 2008. El
tercer elemento es el más completo, ya que involucra el SDK y, además, incluye
las actualizaciones para Visual Studio 2008, así como las plantillas necesarias
para el desarrollo de aplicaciones Silverlight. En forma independiente del ele-
mento elegido, la descarga y su posterior instalación siguen el patrón de cualquier
aplicación bajo Windows. Basta con seguir los pasos provistos por el asistente para
lograr una correcta instalación. Podremos comprobar que las herramientas se han
instalado de manera correcta creando un nuevo proyecto desde Visual Studio
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
58
,
Al momento de escribir este libro, se realizó el anuncio por parte de Microsoft de la nueva
versión de Silverlight: Silverlight 3, versión que se encuentra en etapa beta. Si instalamos
esta versión, no podremos seguir trabajando con la 2, que es la utilizada en este libro. Es re-
comendable usar máquinas virtuales para instalar versiones beta.
NUEVAS VERSIONES DE SILVERLIGHT
03_Silverlight.qxp 9/30/09 1:29 PM Page 58
2008. Al crear el nuevo proyecto (menú Archivo/Nuevo/Proyecto…), deberemos tener
la capacidad de ver el submenú relacionado con Silverlight en el árbol de tipos de
proyectos, dentro del lenguaje de programación elegido. Al seleccionarlo, se verán
las plantillas como se muestran en la siguiente figura.
Figura 3. Silverlight con C#. Al crear un proyecto, vemos plantillas de Silverlight.
Silverlight 2 con Visual Studio
Si en el capítulo anterior identificamos a Expression Blend 2 como la herramienta
ideal para el diseñador gráfico y para crear interfaces visuales en aplicaciones de
software, podemos decir que Visual Studio 2008 es la ideal para los desarrolladores
de software. En este grupo se incluyen tanto los programadores o codificadores,
como los arquitectos de software, aseguradores de la calidad del producto y otros
relacionados con la generación de la pieza de software. Esto quiere decir que, con
Visual Studio 2008, nos focalizaremos en las líneas de código, por lo que el trabajo
realizado sobre las aplicaciones estará planteado desde esta óptica y no relacionado
en forma directa con la interfaz propiamente dicha.
Silverlight para desarrolladores
59
RRR
Es posible traducir a Interfaz de usuario el nombre que comúnmente podremos encontrar en
ingeniería informática y que hace referencia a UI (User Interface en inglés). Este término se
refiere a los componentes visuales involucrados en el software y que se relacionarán con el
usuario que lo utilice.
EL NOMBRE DE LA INTERFAZ DE USUARIO
03_Silverlight.qxp 9/30/09 1:29 PM Page 59
Figura 4. La caja de herramientas de Visual Studio 2008.
De todas maneras, si bien es posible utilizar esta herramienta para realizar todo el
proceso, al mismo tiempo el desarrollador no debe olvidar la interfaz visual, ya que
su código tendrá que adaptarse a las necesidades que se pudieran plantear tanto por
el usuario como por el diseñador. Como dijimos en capítulos anteriores, siempre se-
rá preferible, dentro del grupo de desarrollo o producción de software, contar con
las habilidades y roles necesarios para generar el producto, dejando que cada uno,
desde su rol y experiencia, realice el trabajo designado. Entonces, hacer uso de las dos
herramientas, Visual Studio 2008 y Expression Blend 2, creará un ambiente de de-
sarrollo ideal, porque tiene en cuenta los roles involucrados y preocupados por satis-
facer las necesidades de sus áreas de interés, las cuales representan, en cierta medida,
las necesidades del cliente. Como resultado, se obtendrá una mejor experiencia por
cada una de las partes involucradas, ya que cada una estará enfocada en resolver el
dominio de su problema y no, el de otros. Con esto queremos destacar que, si bien
el desarrollador se encarga de la lógica y del código, no debería olvidar lo relaciona-
do con interfaces gráficas, por lo que tener conocimientos de Expression Blend 2,
aunque sea en menor medida que de Visual Studio 2008, le otorgará mayor criterio
a la hora de entender e implementar lo que el diseñador gráfico le proporcione.
Con Visual Studio 2008, no sólo podremos crear aplicaciones Silverlight, sino que
además nos es posible enriquecerlas desde el punto de vista del código. En la barra
de herramientas, notaremos que existen controles y componentes que no son mos-
trados en Expression Blend 2. Esto se debe a que los componentes, como Calendar,
DataGrid o DatePicker, son ideales para la interacción con datos y sólo se muestran
desde el inicio para los desarrolladores, aunque no para los diseñadores, lo que no
significa que no podamos utilizarlos desde Expression Blend 2. Si exploramos con
mayor profundidad dentro de las aplicaciones Silverlight creadas desde Visual
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
60
03_Silverlight.qxp 9/30/09 1:29 PM Page 60
Studio 2008, notaremos que, como todo desarrollo profesional de software, es
posible agregar diferentes capas o niveles de código a esta aplicación. Se podrá, por
ejemplo, consumir información desde un servicio web remoto y desplegar estos
datos a los usuarios. Hablaremos más de este tema en el capítulo 7.
Figura 5. Agregado de una referencia web a nuestra aplicación Silverlight.
Otra de las cualidades más interesantes las presenta el asistente de escritura de có-
digo IntelliSense, que se usa, en especial, para la escritura de código manejado (C#,
Visual Basic.Net, etcétera), pero en este caso con soporte total para XAML, para
acelerar la producción de estas líneas de código.
Figura 6. IntelliSense para XAML, mostrando
las propiedades disponibles de un componente TextBlock.
Silverlight para desarrolladores
61
03_Silverlight.qxp 9/30/09 1:29 PM Page 61
Por último, una de las capacidades más importantes que tiene Visual Studio 2008
cuando trabajamos con aplicaciones Silverlight es la depuración de código en
tiempo de ejecución. Con esta característica, heredada del desarrollo tradicional
de aplicaciones, podremos colocar puntos de interrupción en nuestro código y
movernos línea a línea una vez que la aplicación esté trabajando. La ventaja de
esta posibilidad radica en que, si encontramos un error en tiempo de ejecución de
nuestra aplicación, podremos depurarla paso a paso para hallar el problema. Esto
resultaría en extremo complicado si tuviéramos que hacer el trabajo mediante la
inspección de las líneas y el cálculo de los estados de las variables y objetos en cada
paso. Para lograrlo, podremos agregar un punto de interrupción con un clic del
mouse en la parte extrema izquierda de nuestro código por cada línea en la que
queramos que la ejecución se detenga.
Figura 7. Algunos puntos de interrupción en nuestro código.
Cuando ejecutamos nuestra aplicación Silverlight, notaremos que la ejecución
del código se detiene en cada uno de los puntos de interrupción declarados, don-
de podemos inspeccionar las variables y objetos en el estado que se encuentren
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
62
RRR
Si no se encuentra visible la barra de herramientas de Visual Studio 2008, podemos hacerla
aparecer con la combinación de teclas CTRL+ALT+X, dependiendo del tipo de configuración
que hayamos elegido inicialmente, o si no, desde el menú Ver/Caja de Herramientas.
BARRA DE HERRAMIENTAS EN VISUAL STUDIO 2008
03_Silverlight.qxp 9/30/09 1:29 PM Page 62
en ese momento. En la figura que aparece a continuación, se muestra cómo el
código se detiene, y uno de los objetos es inspeccionado.
Figura 8. El código es detenido para evaluar el estado de los objetos.
Microsoft Visual Studio 2008 no es sólo una potente herramienta para el desa-
rrollo de software convencional, sino que, además, todas sus prestaciones pue-
den ser usadas para el desarrollo de aplicaciones Silverlight. Por esto, así como
el diseñador visual encuentra su lugar en Expression Blend 2, los desarrolladores
de código lo harán en Visual Studio 2008.
Crear la primera aplicación con Visual Studio 2008
En el capítulo anterior, pudimos crear un reproductor de videos con Expression Blend 2
y Silverlight. En este caso, y conociendo más a fondo las prestaciones de Visual Studio
2008, crearemos otra aplicación Silverlight, pero con el enfoque en la manipulación
de datos. Para este caso, haremos un buscador de productos, con controles que ac-
tuarán de filtro de búsqueda y una lista de registros o grilla que muestre los resultados
encontrados. En este ejemplo, también usaremos LinQ para realizar consultas sobre
objetos, características que trataremos con mayor profundidad en el capítulo 7.
Como primer paso, es necesario crear una nueva aplicación Silverlight 2 desde Visual
Studio 2008. Esto lo logramos desde al menú Archivo y, luego, Nuevo proyecto. En el
árbol de soluciones, debemos buscar la opción de proyectos Silverlight para ver las
plantillas de este tipo de proyectos. Una vez seleccionado el lenguaje de programación
que usaremos, nos posicionamos sobre el tipo de proyecto Silverlight donde podre-
mos ver las plantillas disponibles. En este caso, seleccionaremos la plantilla Aplicación
de Silverlight para poder probar directamente nuestro proyecto; para ello, utilizaremos
Silverlight para desarrolladores
63
03_Silverlight.qxp 9/30/09 1:29 PM Page 63
alguna aplicación ASP.net existente o crearemos una página de prueba para nues-
tra aplicación. Si no vemos las plantillas Silverlight disponibles, usamos Visual
Studio 2008 o superior y ya hemos instalado los aditamentos mencionados en el
capítulo 1, es necesario asegurarnos de haber seleccionado la versión correcta de
Microsoft .Net Framework desde la lista desplegable en la parte superior dere-
cha del asistente para creación de proyectos, como podemos ver a continuación.
Figura 9. Es importante seleccionar la versión 3.5
de Microsoft .Net Framework para poder ver las plantillas de Silverlight.
Una vez cumplidos los pasos anteriores, Visual Studio nos preguntará sobre la
modalidad que utilizaremos para depurar la aplicación Silverlight, y nos permi-
tirá elegir entre las siguientes opciones:
• Crear un nuevo proyecto ASP.net: esta opción agregará un proyecto adicional del
tipo ASP.net a la solución e incrustará, de manera automática, nuestro proyecto
Silverlight a la página por defecto. Cuando depuremos la solución, Visual Studio
abrirá la página ASP.net para mostrar el componente Silverlight creado por nosotros.
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
64
RRR
En varias ocasiones, hablaremos de tiempos de ejecución y tiempo de compilación. Tiempo de
compilación hace referencia al momento en el que nuestro código es transformado en un ejecuta-
ble. Tiempo de ejecución alude, en cambio, al momento en que nuestro código se ejecuta.
TIEMPO DE EJECUCIÓN
03_Silverlight.qxp 9/30/09 1:29 PM Page 64
• Generación automática de una página: en este caso, Visual Studio no creará nin-
guna página ni proyecto adicional a la solución y sólo veremos el proyecto
Silverlight en el cual trabajaremos. Cuando intentemos depurar la aplicación Sil-
verlight, Visual Studio creará una página de manera dinámica en la que podremos
ver y probar el funcionamiento de nuestro componente Silverlight.
• Vincular el control Silverlight: si ya contamos con un sitio web previamen-
te creado, podremos usar esta opción para vincular el proyecto Silverlight con
aquél y depurarlo basado en esta implementación existente. Deberemos selec-
cionar esta opción cuando queramos trabajar en forma directa sobre nuestras
implementaciones web y hacer interactuar nuestro proyecto Silverlight con el
ambiente real donde será desplegado.
Figura 10. En la imagen, vemos las tres opciones
disponibles para crear nuestra aplicación Silverlight.
Para este ejemplo, seleccionaremos la segunda opción, ya que no necesitaremos in-
teractuar con nuestra aplicación Silverlight de manera externa o desde el navegador
del cliente. Una vez creado el proyecto, Visual Studio 2008 nos presentará el lienzo
Silverlight para desarrolladores
65
RRR
La lista de lenguajes disponibles en Visual Studio varía sobre la base de los que hayamos insta-
lado junto con la herramienta. En una instalación típica, podremos elegir entre Visual C++, C#,
Visual Basic.net y J#. Para poder usar lenguajes de otros fabricantes, deberemos adquirirlos
desde sus respectivas páginas webs.
LENGUAJES DISPONIBLES
03_Silverlight.qxp 9/30/09 1:29 PM Page 65
de dibujo de Silverlight y, en la misma pantalla, el código XAML que representa este
lienzo. Al igual que Expression Blend 2, el código inicial se ve como sigue:
UserControl x:Class=”SilverlightApplication1.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=”Layout” Background=”White”
/Grid
/UserControl
La principal desventaja que presenta trabajar con Visual Studio 2008 es que no po-
dremos modificar el lienzo directamente, como en el caso de Expression Blend 2,
sino que deberemos trabajar todo desde el código XAML, lo que requerirá de no-
sotros mayor dominio de éste para conseguir el resultado final.
Figura 11. Vista inicial de una aplicación Silverlight creada con Visual Studio 2008.
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
66
_`
Visual Studio 2008 tiene la particularidad de soportar el desarrollo para diferentes versiones de
.Net Framework. Gracias a ello, se convierte en una herramienta versátil, que permite editar
proyectos creados en versiones anteriores de Visual Studio así como crear proyectos para ver-
siones previas a la última versión del Framework.
VISUAL STUDIO Y LAS VERSIONES DE .NET FRAMEWORK
03_Silverlight.qxp 9/30/09 1:29 PM Page 66
En este ejemplo, haremos uso del contenedor Grid para agrupar y ordenar nuestros
elementos. Por un lado, necesitaremos alguna forma de permitir que el usuario
escriba lo que quiere buscar, capturando dicha entrada y proporcionando la posi-
bilidad de activar la búsqueda. Esto podemos conseguirlo mediante un compo-
nente TextBox y un componente Button. Estos controles deberemos alinearlos de tal
manera que se vean uno al lado del otro. Para conseguir este efecto, agregaremos un
par de filas y de columnas al contenedor Grid inicial de la siguiente manera:
Grid x:Name=”Layout” Background=”White”
Grid.RowDefinitions
RowDefinition Height=”40”/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
/Grid
El tag Grid.RowDefinitions deberemos utilizarlo para agrupar la cantidad de filas
que contendrá esta grilla; cada elemento RowDefinition representará específica-
mente una fila de la grilla, pudiendo definir por cada una sus dimensiones. Por otro
lado, el tag Grid.ColumnDefinitions representa la colección de columnas que con-
tendrá la grilla, pudiendo definir elementos ColumnDefinition dentro de ésta, los
que especificarán cada una de las columnas por visualizar. La grilla definida sólo ser-
virá como organizador de los demás controles y componentes y no para mostrar los
datos propiamente dichos. El siguiente paso consiste en agregar un TextBox y un bo-
tón, los que ubicaremos en la primera fila, y primera y segunda columna de nues-
tra grilla. Podemos ver el resultado en el siguiente código:
Silverlight para desarrolladores
67
RRR
En los capítulos se hace referencia a controles y componentes. Éstos deben ser entendidos como
piezas de software, código funcional encapsulado para su posterior reutilización. Los controles
suelen tener comportamiento visual mientras que los componentes, no.
CONTROLES Y COMPONENTES
03_Silverlight.qxp 9/30/09 1:29 PM Page 67
TextBox Grid.Row=”0” Grid.Column=”0”
x:Name=”txtBusqueda” Margin=”5,5,5,5”/TextBox
Button Grid.Row=”0” Grid.Column=”1” Width=”100”
HorizontalAlignment=”Right” Margin=”0,5,5,5”
Content=”Buscar”/Button
Para ubicar los componentes en el área de la grilla, es necesario determinarlo en el mis-
mo control y no, como podríamos estar acostumbrados en HTML o lenguajes simila-
res, dentro de la definición de la fila y la columna. Por este motivo, haremos uso del
atributo Grid.Row y Grid.Column para determinar la celda en la cual se visualizará el con-
trol. La colección de filas y de columnas se representa mediante un índice con base 0
por lo que, si hacemos referencia a la primera fila y a la primera columna, tendremos
que usar el 0 (cero) en ambos casos. Otros de los atributos que podemos observar es el
de x:Name para el componente TextBox. Con él, accederemos a la información escrita
por el usuario para hacer la búsqueda respectiva; el atributo Margin nos permite agre-
gar al control márgenes en pixeles para que no cubra la totalidad de la celda (es posi-
ble asignarles márgenes izquierdos, superiores, derechos e inferiores, en ese orden, se-
parados por comas). En el caso del botón, el atributo Content representa el texto por
mostrar dentro del componente. En el siguiente paso agregaremos una grilla con ca-
pacidades de manipulación de datos. Para esto, deberemos seleccionarla y arrastrarla
desde la barra de herramientas de Visual Studio. Al hacerlo, veremos que, además del
código XAML, también se adicionará una nueva referencia a nuestro proyecto. Esta re-
ferencia es System.Windows.Controls.Data y es necesaria para utilizar aquellos compo-
nentes con soporte de enlazado de datos, en este caso el control DataGrid.
Figura 12. Si arrastramos y soltamos un DataGrid a nuestro proyecto,
accederemos a un control listo para usar con la capacidad de desplegar registros.
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
68
03_Silverlight.qxp 9/30/09 1:29 PM Page 68
Este DataGrid también necesitará ser asignado a una fila y a una columna dentro
de la grilla general, de la siguiente manera:
data:DataGrid Grid.Row=”1” Grid.Column=”0”
x:Name=”GrillaDeProductos”
Grid.ColumnSpan=”2” AutoGenerateColumns=”True”
/data:DataGrid
Figura 13. Lista de referencias en nuestro proyecto, incluyendo
System.Windows.Controls.Data para el manejo del DataGrid.
Una vez más, los atributos Grid.Row y Grid.Column son utilizados para posicio-
nar este componente en una de las celdas de la grilla, aunque en este caso apa-
rece un nuevo atributo llamado Grid.ColumnSpan. Este atributo es necesario para
decirle al DataGrid que debe emplear u ocupar las dos columnas de la fila en la
cual se encuentra. Si obviáramos este parámetro, obtendríamos un resultado no
deseado, como podemos ver en la figura de la siguiente página.
Silverlight para desarrolladores
69
RRR
Como estamos trabajando con la última versión del lenguaje C#, encontraremos mejoras que
facilitarán la rápida escritura del código. En la versión 2008 del lenguaje, no se requiere que
escribamos el contenido de los get y set en las propiedades y sus respectivas variables privadas,
ya que lo hará por nosotros cuando se genere el programa.
NUEVO C#
03_Silverlight.qxp 9/30/09 1:29 PM Page 69
Figura 14. Al no especificar cuántas columnas ocupará el DataGrid, éste
sólo se enfoca en la primera, dando un aspecto no deseado para este caso.
Otro atributo nuevo que aparece es el AutoGenerateColumns, que especifica que
las columnas del DataGrid se crearán por cuenta propia sobre la base de la infor-
mación enviada, por lo que, si nuestra colección de datos posee N columnas, éstas
serán representadas por el componente. En este punto, ya tenemos toda la interfaz
visual creada, por lo tanto, pasaremos a crear el código C# que realice las búsquedas
basadas en la entrada del usuario. Sobre el proyecto, agregaremos una nueva clase
C# (productos.cs) que usaremos como entidad contenedora de datos. Esto podemos
lograrlo por medio de un clic con el botón secundario del mouse sobre el proyecto
Silverlight y con la adición de un nuevo ítem. En el asistente, seleccionaremos la
opción de código y, a continuación, la plantilla para nuevas clases.
Esta clase debe contener la descripción de todos los campos que necesitaremos
desplegar o por los que realizaremos búsquedas en nuestro código. Al tratarse de la
representación de productos, ésta podría contener algunas propiedades como iden-
tificador del producto, nombre del producto, descripción, precio, cantidad en stock
y otras que se adecuen al negocio. La clase producto debería quedar como sigue:
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
70
RRR
Intellisense resulta extremadamente útil para completar código. Desde Visual Studio podemos
activarlo con la combinación CTRL+J. En el desarrollo de aplicaciones Silverlight no sólo es
posible usar Intellisense en código C#, también está disponible para código XAML.
MICROSOFT INTELLISENSE
03_Silverlight.qxp 9/30/09 1:29 PM Page 70
public class producto
{
public long ID_Producto
{
get;
set;
}
public string Nombre
{
get;
set;
}
public string Descripcion
{
get;
set;
}
public decimal Precio
{
get;
set;
}
public int Stock
{
get;
set;
}
}
El siguiente paso es enlazar el evento click del botón a nuestro código C#. Podemos
hacerlo con facilidad desde el código XAML de nuestra aplicación, si escribimos el
nombre del evento en el botón y dejamos que Visual Studio complete el código
cuando presionamos la tecla TAB, como podemos ver en la siguiente figura.
Silverlight para desarrolladores
71
03_Silverlight.qxp 9/30/09 1:29 PM Page 71
Una vez generado el evento, el código XAML se verá de la siguiente manera:
Button Grid.Row=”0” Grid.Column=”1” Width=”100”
HorizontalAlignment=”Right” Margin=”0,5,5,5”
Content=”Buscar” x:Name=”Button1”
Click=”Button1_Click”/Button
Y el código C# de nuestra aplicación tendrá el siguiente aspecto:
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
}
}
La función Button1_Click se ejecutará cada vez que el usuario presione el botón
en la interfaz. Por tal motivo, deberemos agregar la lógica de búsqueda dentro
de esta función. Pero, antes de realizar esta lógica, es necesario contar con los da-
tos sobre los cuales trabajaremos. Para esto, crearemos una lista genérica de pro-
ductos y la cargaremos con datos suficientes para poder hacer búsquedas sobre
ellos. La carga de la lista podremos dispararla desde una función privada que se-
rá llamada una única vez cuando la aplicación se cargue en primera instancia. Es-
to podemos lograrlo llamando el llenado de la lista desde la función Page en nues-
tro código similar al siguiente:
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
72
RRR
Todos los controles en Silverlight poseen una serie de eventos. Estos eventos representan si-
mulaciones de acciones reales en la interfaz gráfica. El clic del ratón, una tecla presionada, el
conteo de un reloj son reacciones a cuestiones cotidianas de las aplicaciones. A estas reaccio-
nes, las llamamos eventos.
EVENTOS
03_Silverlight.qxp 9/30/09 1:29 PM Page 72
public Page()
{
InitializeComponent();
CargarLista();
}
private Listproducto productos;
private void CargarLista()
{
//Inicializamos la lista de productos
productos = new Listproducto();
//Cargamos la lista de productos con productos
productos.Add(new producto()
{
ID_Producto = 1,
Nombre = “PC Básica”,
Descripcion = “PC de escritorio básica”,
Precio = 1500,
Stock = 10
});
productos.Add(new producto()
{
ID_Producto = 2,
Nombre = “PC Superior”,
Descripcion = “PC de escritorio superior”,
Precio = 3500,
Stock = 50
});
productos.Add(new producto()
{
ID_Producto = 3,
Nombre = “PC Notebook”,
Descripcion = “PC tipo Notebook”,
Precio = 2500,
Stock = 40
});
Silverlight para desarrolladores
73
03_Silverlight.qxp 9/30/09 1:29 PM Page 73
productos.Add(new producto()
{
ID_Producto = 4,
Nombre = “PC NetBook”,
Descripcion = “PC tipo NetBook”,
Precio = 2000,
Stock = 450
});
productos.Add(new producto()
{
ID_Producto = 5,
Nombre = “SmartPhone”,
Descripcion = “Teléfono SmartPhone”,
Precio = 500,
Stock = 55
});
}
Una vez cargados los elementos en la lista, sólo nos queda realizar la búsqueda
sobre la base de las entradas del usuario. Para acelerar las consultas, usaremos
LinQ sobre colecciones. La función enlazada al evento click del botón deberá
tener un aspecto similar al siguiente:
private void Button1_Click(object sender, RoutedEventArgs e)
{
IEnumerableproducto q = from c in productos
where c.Nombre.Contains(this.txtBusqueda.Text)
|| c.Descripcion.Contains(this.txtBusqueda.Text)
select c;
this.GrillaDeProductos.ItemsSource = q;
}
Si usamos la lista genérica productos, realizamos una consulta donde la cláusula
where restringe la búsqueda a todos los registros donde el nombre o la descrip-
ción del producto concuerden con lo introducido por el usuario, en su totalidad
o sólo en una parte. El equivalente a esto en T-SQL sería mediante el uso de:
Nombre like %DATO DEL USUARIO% OR Descripcion like %DATO DEL USUARIO%.
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
74
03_Silverlight.qxp 9/30/09 1:29 PM Page 74
Por último, seleccionamos los valores resultantes de la búsqueda y se le asignan
a la variable q, que será asignada a la propiedad ItemsSource del DataGrid para
que lo tome como su fuente de datos.
Figura 15. Nuestra aplicación muestra los datos
filtrados por la palabra clave introducida por el usuario.
Podemos extender la funcionalidad de nuestra aplicación y del componente DataGrid
si agregamos algunas propiedades. Este control es lo suficientemente versátil como pa-
ra permitir modificar su apariencia y su comportamiento. A continuación, agregamos
la capacidad de que el usuario pueda reordenar las columnas de la grilla de resultados,
y además le asignamos colores al fondo de cada uno de los ítems desplegados:
data:DataGrid Grid.Row=”1” Grid.Column=”0”
x:Name=”GrillaDeProductos”
Grid.ColumnSpan=”2” AutoGenerateColumns=”True”
CanUserReorderColumns=”True” CanUserResizeColumns=”False”
AlternatingRowBackground=”LightBlue” RowBackground=”LightGreen”
/data:DataGrid
Las propiedades CanUserReorderColumns y CanUserResizeColumns permiten que
el usuario mezcle las columnas arrastrándolas y soltándolas, y que pueda o no re-
dimensionar el tamaño de las columnas. Para especificar los colores de las filas,
usamos RowBackground, que asignará el color de fondo para la fila, y Alternating
RowBackground, que configurará el color de fondo de las filas alternativas (por
cada fila par, usará este color en lugar del configurado en RowBackground).
Silverlight para desarrolladores
75
03_Silverlight.qxp 9/30/09 1:29 PM Page 75
Figura 16. La imagen muestra cómo el usuario puede
reordenar las columnas una vez activada la propiedad.
Interoperabilidad con Expression Blend 2
Si bien dijimos que el desarrollador de software debe enfocarse en las líneas de códi-
go y en la resolución del dominio del problema, existirán oportunidades en las que
necesite hacer modificaciones en la interfaz visual o, en casos extremos, crearla por su
cuenta. En este capítulo, pudimos ver que Visual Studio 2008 por sí solo no resulta
tan versátil como es necesario en cuanto a diseño visual de aplicaciones Silverlight. Só-
lo tenemos una vista previa de lo que diseñamos en XAML, por lo que nos demanda
un conocimiento avanzado sobre la descripción de cada control y cada componente,
sus jerarquías, atributos y composiciones. Esto, hasta no conseguir suficiente expe-
riencia, podría transformarse en una situación un tanto frustrante. Por ello, es reco-
mendable tener instaladas las dos herramientas, aunque sólo nos dediquemos a una
de las ramas del desarrollo del producto. Si lo hacemos, podremos abrir el proyecto
en el que estemos trabajando con Expression Blend 2 para su edición sin la necesidad
de cerrar la solución o abrirla de manera externa. Si queremos editar nuestro proyecto
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
76
RRR
Es recomendable que siempre tengamos instalado Expression Blend 2 en nuestro equipo cuando
desarrollemos aplicaciones Silverlight. Sin importar si sólo nos dedicamos a la producción de
código, esta herramienta nos ayudará a acelerar la producción de código XAML y nos facilitará
la creación de contenido visual.
EXPRESSION BLEND 2
03_Silverlight.qxp 9/30/09 1:29 PM Page 76
con Expression Blend 2, lo único que necesitamos es seleccionar la página XAML por
editar y, con el botón secundario del mouse, pulsar Abrir en Expression Blend….
Figura 17. Con el botón secundario del ratón,
es posible abrir nuestro proyecto en Expression Blend 2.
Expression Blend 2 cargará el proyecto representándolo en su árbol de soluciones. Las
modificaciones que hagamos en esta solución se verán reflejadas, de forma automática,
en Visual Studio 2008. En la figura siguiente, se observa, a la derecha, el árbol de la so-
lución y, a la izquierda, la lista de controles presentes en el proyecto. Editar las propie-
dades visuales puede resultar más simple desde aquí que desde Visual Studio 2008.
Figura 18. A la derecha, el árbol de la solución
representado de igual manera que en Visual Studio 2008.
Silverlight para desarrolladores
77
03_Silverlight.qxp 9/30/09 1:29 PM Page 77
Para completar el ejemplo, modificaremos la apariencia del componente DataGrid.
Primero lo seleccionamos en la lista de controles y luego, en la pestaña Propiedades,
modificamos los colores usados para cada uno de los registros, así como el fondo.
Figura 19. Una vez que seleccionamos el DataGrid,
modificamos sus propiedades en la pestaña Propiedades.
Podríamos ejecutar la aplicación desde Expression Blend 2 para ver sus resultados,
aunque en este caso, una vez guardados los cambios, cerraremos esta aplicación y vol-
veremos a Visual Studio 2008. Si éste ha detectado cambios en el XAML, nos pedirá
autorización para recargar el contenido. En este caso, aceptaremos las modificaciones
ya que representan los cambios realizados. Una vez que la aplicación haya sido recar-
gada, depuramos el código presionando la tecla F5. Luego, si inspeccionamos el códi-
go XAML del DataGrid generado por Expression Blend 2, notaremos cambios:
data:DataGrid Grid.Row=”1” Grid.Column=”0”
x:Name=”GrillaDeProductos”
Grid.ColumnSpan=”2” AutoGenerateColumns=”True”
CanUserReorderColumns=”True” CanUserResizeColumns=”False”
data:DataGrid.Background
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF462BEE”/
GradientStop Color=”#FFE1E0EA” Offset=”1”/
/LinearGradientBrush
/data:DataGrid.Background
data:DataGrid.RowBackground
3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA
78
03_Silverlight.qxp 9/30/09 1:29 PM Page 78
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF92B6C7”/
GradientStop Color=”#FF51BFF0” Offset=”1”/
/LinearGradientBrush
/data:DataGrid.RowBackground
data:DataGrid.AlternatingRowBackground
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF657446”/
GradientStop Color=”#FFE0F2BA” Offset=”1”/
/LinearGradientBrush
/data:DataGrid.AlternatingRowBackground
/data:DataGrid
Figura 20. Nuevo aspecto visual del DataGrid basado
en las modificaciones realizadas en Expression Blend 2.
Silverlight para desarrolladores
79
… RESUMEN
Visual Studio 2008 brinda al desarrollador elementos para acelerar la producción de código,
así como también controles y componentes exclusivos para la resolución de problemas
planteados en el proceso de producción del software. Visual Studio 2008 también deja
modificar la parte visual con herramientas externas como Expression Blend 2. Demuestra así
su versatilidad en el desarrollo de software y permite compartir visiones entre el productor
de las interfaces gráficas y el desarrollador de funcionalidades.
03_Silverlight.qxp 9/30/09 1:29 PM Page 79
80

PREGUNTAS TEÓRICAS
1 ¿Por qué es importante colocar la versión
correcta de Silverlight en la declaración
HTML del componente?
2 ¿Qué es un SDK?
3 ¿Es necesario instalar algún aditamento
para Visual Studio 2008 antes de desarro-
llar con Silverlight 2?
4 ¿Cuál es la diferencia entre Expression
Blend 2 y Visual Studio 2008?
5 ¿Es posible adicionar referencias a servi-
cios web en un proyecto Silverlight 2?
6 ¿Cómo se denomina el mecanismo que
proporciona ayuda en el momento de la es-
critura de código?
7 ¿Contamos, en Visual Studio 2008, con so-
porte para escritura de código XAML?
8 ¿Entre qué opciones podremos elegir al
crear un nuevo proyecto Silverlight 2?
9 ¿Qué ensamblado .Net se referencia en el
momento en el que el control DataGrid es
adicionado a nuestro proyecto Silverlight 2?
10¿Cuál es la diferencia entre usar la propie-
dad AutoGenerateColumns y no usarla en el
control DataGrid?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Para saber más sobre LinQ, ingrese en el
sitio de MSDN (http://msdn.microsoft.
com/es-es) y busque esta tecnología.
2 Para poner en práctica LinQ, trate de mo-
dificar el ejemplo presentado en este capí-
tulo incorporando el precio dentro de los
parámetros del filtro de búsqueda.
3 Intente cambiar los colores utilizados pa-
ra representar los elementos en el control
DataGrid y, así, obtener un nuevo aspecto
en la aplicación.
4 Si el código HTML presentado en este ca-
pítulo le resultó extraño, visite el sitio web
de la W3C para aprender más sobre esta
tecnología: www.w3.org/html.
5 Revise la documentación sobre servicios
web en la dirección http://msdn.microsoft.
com/es-es para saber más sobre este tema.
03_Silverlight.qxp 9/30/09 1:29 PM Page 80
XAML
al extremo
El lenguaje XAML 82
¿Qué es XAML? 82
Declaración de objetos 82
Controles y componentes 83
Controles contenedores
y agrupadores 84
Control Grid 84
Control GridSplitter 89
Control Canvas 92
Control StackPanel 95
Control ScrollViewer 98
Control Border 101
Controles de interacción
con el usuario 103
Control Button 103
Control CheckBox 106
Control RadioButton 110
Control HyperlinkButton 113
Control Image 114
Control ComboBox 117
Control ListBox 124
Control TextBlock 126
Control TextBox 127
Control PasswordBox 130
Control DataGrid 132
Control Calendar 139
Control DatePicker 147
Control ProgressBar 148
Control Slider 152
Resumen 153
Actividades 154
Capítulo 4
Es necesario tener una referencia de cada
uno de los controles y componentes
propuestos por Silverlight. Cada uno
de ellos, su declaración, métodos, eventos
y uso serán tratados en este capítulo,
que servirá como un manual
que nos guiará y ayudará
en la construcción de nuestras
aplicaciones Silverlight.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
04_Silverlight.qxp 9/30/09 1:31 PM Page 81
EL LENGUAJE XAML
Hasta este momento, ya hemos hablado de Silverlight, su arquitectura, alcances y
restricciones. Hemos usado dos de las principales herramientas para desarrollar
con Silverlight, así como realizado algunos ejemplos iniciales para poder mover-
nos con mayor soltura, además de entender mejor esta tecnología. Es momento,
entonces, de hacer un recorrido más exhaustivo sobre cada uno de los controles y
componentes que podemos encontrar en Silverlight. En este capítulo, veremos ca-
da uno de los elementos representados con XAML provistos por Silverlight, sus
propiedades y sus usos elementales desde C#. Esta parte del libro puede ser con-
siderada como una referencia a los controles de Silverlight y XAML.
¿Qué es XAML?
XAML es un lenguaje declarativo que tiene su raíz en el XML. Con XAML, es
posible declarar objetos que representen una interfaz gráfica común entre dife-
rentes plataformas. Uno de los problemas acarreado por las plataformas, ya sean
de escritorio, webs, u otras, así como distintos sistemas operativos, Windows, Linux,
etcétera, consiste en la imposibilidad de compartir entre ellas los mismos ele-
mentos visuales que componen la interfaz. Un acercamiento a esta solución es el
HTML, aunque éste sólo es aplicado a la Web, y no se pueden compartir los mis-
mos elementos en aplicaciones de escritorio. XAML, entonces, une bajo el mismo
lenguaje declarativo la posibilidad de utilizar una única interfaz gráfica en diferen-
tes ambientes. En el caso de aplicaciones de escritorio bajo Windows, mediante
WPF, y, en la Web, por medio de Silverlight.
Es necesario tener cierto cuidado cuando escribimos XAML, ya que éste es sensible
a mayúsculas y minúsculas. Esto quiere decir que deberemos prestar mucha aten-
ción cuando queramos usar cualquier control o componente en Silverlight, ya que
un cambio de mayúsculas a de minúsculas hará que la aplicación deje de funcionar.
Declaración de objetos
Los objetos en XAML pueden ser declarados de diferentes formas. Pero, en cual-
quier caso, un tag inicial deberá siempre ser cerrado al terminar de usarlo. Estos
objetos suelen presentar dos formas tradicionales de declaración.
Objeto
/Objeto
Es importante que notemos la diferencia entre el tag de apertura y el de cierre.
Como vemos, para poder cerrar un objeto en XAML, es necesario utilizar los
4. XAML AL EXTREMO
82
04_Silverlight.qxp 9/30/09 1:31 PM Page 82
caracteres /, por lo demás, el nombre del objeto de apertura y su sintaxis son idén-
ticos. Esto quiere decir que se respetan las mayúsculas y minúsculas. También es
posible, si el tag lo permite, su apertura y cierre en una sola línea.
Objeto /
En el caso anterior, el tag es abierto al comienzo y cerrado al final con los mis-
mos caracteres (/). Por otro lado, al ser un lenguaje basado en XML, con nodos
y subnodos, si el modelo de objeto lo permite es posible declarar un elemento
dentro de otro, lo que permitirá crear elementos mucho más ricos. Esto adicio-
nará, además, versatilidad y simpleza en el momento de tener que crear compo-
nentes más complejos, como botones que presenten como fondo un video y no
un color plano, o agregar casillas de verificación a una lista desplegable. Podemos
anidar uno o más elementos de la siguiente forma.
Canvas
Button/Button
/Canvas
CONTROLES Y COMPONENTES
A lo largo de los tres primeros capítulos, nos hemos encontrado con algunos de los
controles y componentes disponibles en Silverlight: controles contenedores de otros
controles; controles utilizados para mostrar videos, imágenes o datos; así como con-
troles que capturan el comportamiento del usuario sirviéndonos de nexo entre éste
y la aplicación creada. Este comportamiento es iniciado, por lo general, con la
ayuda de un evento. Alguno de estos eventos son comunes a todos los controles
Silverlight y entre ellos podemos encontrar los siguientes:
Controles y componentes
83
_`
Un intento de acercar la conmutación de la interfaz gráfica entre plataformas fue la creada por
Microsoft por medio de los archivos HTA (HTML Application). Aquí, archivos con tags HTML re-
gulares podían ser ejecutados en Windows sin la necesidad explícita de un navegador web.
ARCHIVOS HTA
04_Silverlight.qxp 9/30/09 1:31 PM Page 83
• GotFocus: este evento se disparará cuando el control tome el foco de la acción. Pue-
de ser usado cuando el usuario navega de un control a otro en nuestra aplicación
Silverlight, pulsando la tecla TAB o presionando con el ratón.
• IsEnabledChanged: si modificamos el estado del control, pasándolo de habilitado
a no habilitado, este evento nos pondrá en alerta sobre ese cambio.
• KeyDown: en este caso, si el usuario presiona una tecla cuando el control tiene
el foco, el evento se disparará.
• KeyUp: acción contraria a la anterior. Este evento se disparará en el momento en
el que la tecla sea liberada. Esto es, cuando el usuario dejó de presionarla.
• LayoutUpdated: cada vez que exista una modificación visual en el control, ya sea
por adición de otro control, movimiento de las barras de desplazamiento o cam-
bio de tamaño del control, este evento será disparado.
• LostFocus: ésta es la acción opuesta a GotFocus. En el momento en que el con-
trol pierda el foco, el evento nos pondrá en alerta.
• SizeChanged: si el control se modifica en su tamaño, este evento lo comunicará.
Es importante tener presente estos eventos, ya que nos serán de utilidad en la imple-
mentación de nuestro código y en el comportamiento de la aplicación. Si bien algunos
eventos son comunes a todos los controles, la declaración y el uso varían. Veamos
entonces, uno a uno, los controles y lo componentes disponibles, su funcionalidad, su
declaración sintáctica y cómo podemos interactuar con ellos desde nuestro código.
Controles contenedores y agrupadores
Los siguientes controles forman parte de los usados para agrupar o contener otros
controles. Estos controles se utilizan, en especial, para manipular la estructura de
diseño de nuestra aplicación. Con ellos, es posible colocar elementos en diferentes
posiciones, mantenerlos en fijos o desplazarlos por la aplicación como un todo.
Control Grid
El control Grid, o grilla en castellano, está pensado para la representación de filas y
columnas dentro del lienzo de dibujo de Silverlight. Debemos usar este control
cuando necesitemos organizar, de forma estructurada, otros controles Silverlight,
colocando dentro de cada celda de la grilla el o los controles adicionales. Pensemos
en este control como si fuera una planilla de cálculo o, para aquellos desarrollado-
res web, en el tag Table, con sus TR y TD usados en el HTML.
La declaración inicial de un control Grid es simple:
Grid x:Name=”[NombreDelControl]”
/Grid
4. XAML AL EXTREMO
84
04_Silverlight.qxp 9/30/09 1:31 PM Page 84
El tag Grid marca el inicio del control Grid, y debe ser cerrado con su tag finalizador
/Grid. Todos los controles contenidos por el elemento Grid deberán ser escritos en-
tre estos dos tags. Es importante, pero no obligatorio, asignarle un nombre por medio
del atributo x:Name al control Grid (deberemos hacerlo si necesitamos manipularlo en
tiempo de ejecución). Tenemos que declarar las filas y las columnas al inicio de nues-
tro control Grid, pudiendo especificar tantas filas y columnas como necesitemos:
Grid x:Name=”[NombreDelControl]”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
/Grid
El tag Grid.RowDefinitions es el contenedor de la cantidad de filas que incluirá el
control, y debemos colocar dentro de los límites de éste tantos tags RowDefinition
como filas queramos tener. Por su parte, el tag /Grid.RowDefinitions deberá in-
cluirse para marcar el cierre y contenido de las filas definidas. De igual manera, el tag
Grid.ColumnDefinitions tiene un comportamiento similar a Grid.RowDefinitions,
con la clara diferencia que enumera las columnas del control Grid. Debemos colo-
car tantos ColumnDefinition como columnas queramos tener en nuestra grilla. Al
finalizar la lista, cerramos el tag por medio de /Grid.ColumnDefinitions. En el có-
digo anterior, nuestra grilla cuenta con dos filas y tres columnas.
Con la estructura básica de la grilla definida, es posible asignarles atributos a los tags
para modificar su comportamiento. Los primeros atributos son los que especifican
el ancho (Width) y el alto (Height), tanto sea de las columnas como de las filas:
Controles y componentes
85
RRR
Una celda, en un control del tipo Grid, se encuentra conformada por la unión de sus filas y de
sus columnas. El resultado de unir estos dos elementos arrojará un espacio para colocar otros
controles o una celda. Es necesario el par columna y fila para poder obtener esta celda.
UNA CELDA
04_Silverlight.qxp 9/30/09 1:31 PM Page 85
Grid.ColumnDefinitions
ColumnDefinition Width=”60”/
ColumnDefinition Width=”50*”/
ColumnDefinition Width=”20”/
/Grid.ColumnDefinitions
En la definición anterior, cada columna posee un ancho específico, cuyo valor es
representado en pixeles. La segunda columna tiene un valor característico repre-
sentado por un * (asterisco); este signo representa un comodín y significa que la
columna ocupará los pixeles indicados anteriormente más todos los que se en-
cuentran libres, no definidos por las demás columnas.
Si tenemos una grilla que ocupa 400 pixeles de ancho, y contamos con una su-
ma total de columnas, de acuerdo con el ejemplo anterior, de 130 pixeles, la se-
gunda columna ocupará 50 pixeles más 270 pixeles restantes. Esta característica
es importante cuando necesitamos mantener ciertas columnas estáticas y otras
que se adapten sobre la base del ancho del contenedor de nuestra aplicación.
Como ejemplo, podríamos incrustar una aplicación Silverlight, en una página
web, que ocupe el 100% de su ancho. Esta página podría ser visitada por dife-
rentes entornos con distintas resoluciones de pantalla, lo que haría que la pági-
na se adaptase, en ancho, a la configuración del usuario, y lograría que nuestra
aplicación Silverlight también se adaptara a ésta modificando dinámicamente las
columnas que posean un asterisco. Podemos observar el resultado de las confi-
guraciones de las columnas en la figura que vemos a continuación.
Figura 1. En esta imagen, podemos ver
un control Grid configurado usando Expression Blend 2.
4. XAML AL EXTREMO
86
04_Silverlight.qxp 9/30/09 1:31 PM Page 86
Sobre las filas, es posible configurar el alto (Height) como en el siguiente código:
Grid.RowDefinitions
RowDefinition Height=”70*”/
RowDefinition Height=”70”/
/Grid.RowDefinitions
Con características idénticas a las nombradas para las columnas, podremos usar
el comodín * para modificar el alto de las filas de manera dinámica. Si no espe-
cificamos un valor para el alto y el ancho a nivel del tag de la grilla, ésta asumirá
que debe ocupar la totalidad definida por el contenedor. Podremos modificar es-
tos valores agregando en forma manual estos valores:
Grid x:Name=”[NombreDelControl]” Width=”200” Height=”200”
Grid.RowDefinitions
RowDefinition Height=”70*”/
RowDefinition Height=”70”/
...
...
Figura 2. Ancho y alto definidos usando Expression Blend 2.
ShowGridLines, Cursor, ToolTipService.ToolTip son otros atributos que pueden ser
usados a nivel del tag que representa la grilla. ShowGridLines puede contener dos
valores: True (verdadero) o False (falso), y mostrar o no las líneas que definen el
Controles y componentes
87
04_Silverlight.qxp 9/30/09 1:31 PM Page 87
contorno de la grilla, sus filas y columnas. Por su parte, Cursor configura el tipo
de puntero de mouse que se va a mostrar cuando éste se pase por encima del con-
trol de grilla, pudiendo elegir entre Arrow (flecha), Eraser (borrador), Hand (ma-
no), IBean (símbolo de escritura), None (sin icono), SizeNS (cambio de tamaño
norte/sur), SizeWE (cambio de tamaño oeste/este), Stylus (punto de lápiz) y Wait
(reloj de arena de espera). Por último, ToolTipService.ToolTip permite mostrarle
al usuario mensajes emergentes temporales cuando el mouse se posiciona duran-
te determinado tiempo sobre el control de grilla. En el siguiente código, se apli-
can todos los elementos mencionados:
Grid x:Name=”[NombreDelControl]”
ShowGridLines=”True” Cursor=”Eraser”
ToolTipService.ToolTip=”Mi grilla”
Width=”200” Height=”200”
Grid.RowDefinitions
RowDefinition Height=”70*”/
RowDefinition Height=”70”/
...
...
El código anterior deberá mostrar las líneas que delimitan la grilla, un mensaje
desplegable y un cursor con forma de borrador. Todo esto, lo podemos observar
en la imagen que aparece a continuación.
Figura 3. Control Grid configurado con propiedades
para el cursor, líneas divisorias y mensaje emergente.
4. XAML AL EXTREMO
88
04_Silverlight.qxp 9/30/09 1:31 PM Page 88
Es posible también especificar la posición del control en relación con el contenedor
principal. La grilla se puede colocar en cualquiera de las esquinas del contenedor,
así como en el centro, e incluso especificar que ocupe toda una franja, ya sea supe-
rior, inferior, izquierda o derecha de la aplicación Silverlight.
Grid x:Name=”[NombreDelControl]”
ShowGridLines=”True” Cursor=”Eraser”
ToolTipService.ToolTip=”Mi grilla”
HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”
Grid.RowDefinitions
RowDefinition Height=”70*”/
Los atributos HorizontalAlignment y VerticalAlignment hacen que se pueda especifi-
car la distribución de la grilla dentro del contenedor principal. Podremos usar las
propiedades Left (izquierda), Center (centro), Right (derecha) y Stretch (estirado) pa-
ra el atributo HorizontalAlignment. Las propiedades Top (arriba), Center (centro),
Bottom (abajo) y Stretch (estirado) son válidas para el atributo VerticalAlignment. Si
los dos atributos fueran configurados con la propiedad Stretch, la grilla ocuparía todo
el espacio provisto por el contenedor principal, como vemos en la siguiente figura.
Figura 4. Nuestra grilla ocupa el espacio disponible de su contenedor.
Control GridSplitter
GridSplitter no es un contenedor por sí solo, sino que se conjuga con el control
Grid para poder manipular las columnas de este control y desplazarlas libremen-
te. Para poder utilizarlo, en primer lugar, deberemos configurar una grilla que
Controles y componentes
89
04_Silverlight.qxp 9/30/09 1:31 PM Page 89
contenga dos o más columnas, o dos o más filas. GridSplitter utilizará una de
estas filas o columnas para redimensionar las restantes en tiempo de ejecución.
Declaramos un control GridSplitter de la siguiente manera:
basics:GridSplitter x:Name=”[NombreDelControl]” Grid.Row=”[Indice de
fila]” Grid.Column=”[Indice de columna]”
/basics:GridSplitter
Es necesario especificar la fila y la columna en la cual este control se posiciona-
rá. Es importante mencionar que esta fila y columna no deberían ser usadas por
otro control una vez asociado el GridSplitter. El siguiente código muestra la im-
plementación completa de una grilla con un GridSplitter:
Grid x:Name=”LayoutRoot” Width=”400” Height=”300”
Grid.RowDefinitions
RowDefinition /
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition MinWidth=”10” MaxWidth=”200” /
ColumnDefinition Width=”10”/
ColumnDefinition/
/Grid.ColumnDefinitions
basics:GridSplitter x:Name=”miGridSplitter” Grid.Row=”0”
Grid.Column=”1” VerticalAlignment=”Stretch”
HorizontalAlignment=”Center” Background=”#FFDD7676”
Width=”5”/basics:GridSplitter
/Grid
Notemos que la primera columna de la grilla, definida por el tag ColumnDefinition,
posee dos atributos: MinWidth y MaxWidth. Los valores de cada uno representan
4. XAML AL EXTREMO
90
RRR
Podemos intentar la configuración del atributo HorizontalAlignment con el valor Stretch y el atri-
buto VerticalAlignment con el valor Top. Con esta acción, haremos que la grilla ocupe toda la
parte superior del contenedor, dejando espacio en la parte inferior.
CUBRIR PARTE DEL CONTENEDOR
04_Silverlight.qxp 9/30/09 1:31 PM Page 90
los valores mínimos y máximos, en este orden, a los que podrá encogerse o esti-
rarse dicha columna por acción del control GridSplitter. En la figura siguiente,
podemos ver estos elementos funcionando.
Figura 5. GridSplitter aplicado a una grilla con atributos
MinWidth y MaxWidth aplicados en la columna.
En el ejemplo anterior, el control GridSplitter se visualiza y acciona de manera
vertical. Podemos, por otro lado, aplicarlo de forma horizontal. Para lograr esto,
tendremos que aplicar este control a las filas del control Grid y no a sus columnas:
Grid x:Name=”LayoutRoot” Width=”400” Height=”300”
Grid.RowDefinitions
RowDefinition /
RowDefinition Height=”10”/
RowDefinition MaxHeight=”200” MinHeight=”10”/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition MinWidth=”10” MaxWidth=”200” /
ColumnDefinition Width=”10”/
ColumnDefinition /
/Grid.ColumnDefinitions
basics:GridSplitter x:Name=”miGridSplitter” Grid.Row=”0”
Grid.Column=”1” VerticalAlignment=”Stretch”
HorizontalAlignment=”Center” Background=”#FFDD7676”
Width=”5”/basics:GridSplitter
Controles y componentes
91
04_Silverlight.qxp 9/30/09 1:31 PM Page 91
basics:GridSplitter x:Name=”miGridSplitterHorizontal”
Grid.ColumnSpan=”3” Grid.Row=”1” Grid.Column=”0”
HorizontalAlignment=”Stretch” VerticalAlignment=”Center”
Background=”#FFDD7676” Height=”5”/basics:GridSplitter
/Grid
El código anterior realiza algunas variaciones para poder soportar un control
GridSplitter de manera horizontal. En primer lugar, agregamos dos filas más a la
grilla. La fila que soportará el cambio de dimensiones tiene ahora dos atributos,
MinHeight y MaxHeight, que representan el valor mínimo y máximo soportado
por la fila cuando se modifique su altura. Otro cambio es la cantidad de columnas
que ocupará el control GridSplitter, representado por el atributo Grid.ColumnSpan
colocando una unidad por cada columna que se ocupará. El resultado se puede
ver en la siguiente imagen.
Figura 6. En este caso, vemos dos controles GridSplitter
trabajando sobre la misma grilla.
Control Canvas
El control Canvas es el más simple de los contenedores. Su trabajo, como conte-
nedor, es el de incluir otros controles sin una estructura específica. El siguiente
código muestra la declaración del control Canvas:
Canvas x:Name=”[NombreDelControl]”
/Canvas
4. XAML AL EXTREMO
92
04_Silverlight.qxp 9/30/09 1:31 PM Page 92
El objetivo del control Canvas es el de poder agrupar, de forma simple, otros ele-
mentos Silverlight. De esta forma, alterando el comportamiento del control Canvas,
podremos alterar el de todos los controles contenidos en él. Podemos aplicar una
transformación al control Canvas para distorsionarlo, como vemos a continuación.
Figura 7. Aplicando una transformación al control Canvas.
A continuación, podemos ver el código de la figura anterior:
Canvas x:Name=”[NombreDelControl]” HorizontalAlignment=”Stretch”
RenderTransformOrigin=”0.5,0.5”
Canvas.RenderTransform
TransformGroup
ScaleTransform/
SkewTransform AngleX=”-9” AngleY=”-5”/
RotateTransform/
TranslateTransform/
/TransformGroup
/Canvas.RenderTransform
El tag Canvas.RenderTransform especifica el inicio de las diferentes transfor-
maciones que pueda sufrir un control. En este caso, mediante el uso del tag
SkewTransform, se especifican los valores numéricos de la distorsión. Hablare-
mos más sobre transformaciones en el capítulo 5.
Podremos posicionar diferentes controles dentro del elemento Canvas por medio
del atributo Canvas.Left (izquierda) y Canvas.Top (arriba). Estos dos atributos deben
Controles y componentes
93
04_Silverlight.qxp 9/30/09 1:31 PM Page 93
ser especificados en el control contenido y configuran la posición en pixeles con-
tando desde la esquina superior izquierda del control Canvas. En el siguiente
ejemplo, el control del botón se posicionará a 106 pixeles desde la izquierda ex-
trema y 90 pixeles desde la parte superior.
Button Height=”37” Width=”73” Canvas.Left=”106” Canvas.Top=”90”
Content=”Click Aquí”/
Es posible combinar diferentes controles contenedores. Así podríamos usar un
control Grid como contenedor principal y, en sus celdas, agrupar otros controles
mediante el uso del control Canvas. Como dijimos, al agrupar otros controles
dentro de un mismo contenedor, todos los cambios realizados en éste afectarán los
controles incluidos, por lo que podríamos agruparlos para que queden ocultos y
mostrarlos en conjunto y no individualmente. El siguiente código XAML crea un
control Grid con dos columnas y dos filas; coloca dos botones en las filas superiores
y un control Canvas en la fila inferior, que contiene un texto.
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
Button Margin=”46,41,69,69” Content=”Ocultar” x:Name=”BtnOcultar”
Click=”BtnOcultar_Click”/
Button Margin=”46,41,69,69” Grid.Column=”1” Content=”Mostrar”
x:Name=”BtnMostrar” Click=”BtnMostrar_Click”/
Canvas Grid.Row=”1” x:Name=”CanvasContenedor”
TextBlock Margin=”46,66,46,50” Grid.Row=”1” Text=”Mensaje a
mostrar” TextWrapping=”Wrap”/
/Canvas
/Grid
Como vemos en el código anterior, los botones apuntan a dos eventos manejados
por C#. Este código oculta y muestra el control Canvas, ocultando y mostrando, a
su vez, todos los controles contenidos por él.
4. XAML AL EXTREMO
94
04_Silverlight.qxp 9/30/09 1:31 PM Page 94
private void BtnOcultar_Click(object sender, RoutedEventArgs e)
{
this.CanvasContenedor.Visibility = Visibility.Collapsed;
}
private void BtnMostrar_Click(object sender, RoutedEventArgs e)
{
this.CanvasContenedor.Visibility = Visibility.Visible;
}
Podemos ver en la siguiente imagen cómo, al presionar el botón para ocultar el
control Canvas, todo su contenido también se hace invisible.
Figura 8. Una vez presionado el botón Ocultar, el control
Canvas se hace invisible junto con todos sus controles contenidos.
Control StackPanel
Es posible que necesitemos crear una pila de controles, esto es, una sucesión de con-
troles Silverlight que ocupen todo el espacio designado para éste, tanto en ancho como
en alto. Pensemos en controles apilados, uno arriba del otro o uno al lado del otro.
Es posible conseguir esto mediante el control StackPanel. Por lo común, usaremos
el control StackPanel dentro de otros controles contenedores como vimos en el caso
del control Canvas. Para declarar un control StackPanel, usaremos el siguiente código:
StackPanel x:Name=”[NombreDelControl]”
/StackPanel
Controles y componentes
95
04_Silverlight.qxp 9/30/09 1:31 PM Page 95
Al agregar nuevos controles dentro de StackPanel, no necesitaremos configurar
atributos de posiciones debido a que éstos seguirán el flujo establecido por el
StackPanel. Este flujo puede ser horizontal o vertical; para el primer caso, usaremos
el atributo Orientation con el valor Horizontal, como vemos a continuación.
Figura 9. En este caso, tenemos un StackPanel
como contenedor principal y con flujo horizontal.
En la siguiente figura, vemos cómo el flujo de los controles se muestra de manera
vertical; es posible lograr esto cambiando el valor del atributo Orientation a Vertical.
Figura 10. Aquí, el StackPanel como
contenedor principal, está establecido con flujo vertical.
4. XAML AL EXTREMO
96
04_Silverlight.qxp 9/30/09 1:31 PM Page 96
Es importante resaltar que este atributo debe ser declarado dentro del tag StackPanel,
como vemos en el código que aparece a continuación:
StackPanel x:Name=”[NombreDelControl]” Orientation=”[Vertical |
Horizontal]”
Los contenedores, como su nombre lo indica y ya hemos visto, contienen otros
controles. Dentro de esta característica, se incluye la creación dinámica de otros con-
troles y la posterior adición del control creado al contenedor. El siguiente código
crea un nuevo control y lo adiciona al control contenedor StackPanel:
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
/Grid.ColumnDefinitions
StackPanel x:Name=”StackContenedor”
Button Content=”Nuevo Control” Click=”Button_Click”/
/StackPanel
/Grid
En el código anterior, hemos agregado un control Grid con una fila y una columna.
Dentro de la celda creada, un StackPanel y, dentro de éste, un botón. Este botón
disparará un evento en C# con el siguiente código:
private void Button_Click(object sender, RoutedEventArgs e)
{
TextBox textBox = new TextBox();
textBox.Text = “Inserte texto aquí”;
this.StackContenedor.Children.Add(textBox);
}
Cuando el usuario presiona el botón inicial, éste creará una nueva instancia de
un control TextBox, le configurará un texto por mostrar y lo adicionará a la lis-
ta de controles contenidos por el StackPanel. Podemos ver el resultado de pulsar
varias veces el botón en la figura de la siguiente página.
Controles y componentes
97
04_Silverlight.qxp 9/30/09 1:31 PM Page 97
Figura 11. Diferentes controles creados
de manera dinámica a partir de una acción del usuario.
Control ScrollViewer
El control ScrollViewer es un contenedor que tiene la capacidad de mostrar barras
de desplazamientos, tanto verticales como horizontales, dependiendo de su conte-
nido. Declaramos un control ScrollViewer de la siguiente forma:
ScrollViewer x:Name=”[NombreDelControl]”
/ScrollViewer
Podemos manipular la aparición de las barras de desplazamiento dejando que éstas
se generen en forma automática sobre la base del contenido, ocultarlas por com-
pleto o mostrarlas siempre. Para esto, deberemos interactuar con los atributos
HorizontalScrollBarVisibility y VerticalScrollBarVisibility, pudiendo elegir como posibles
valores entre Disabled, Auto, Hidden y Visible. A continuación, vemos los valores
soportados por los atributos HorizontalScrollBarVisibility y VerticalScrollBarVisibility:
• Disabled: esta propiedad hará que, sin importar el contenido que tenga el control
ScrollViewer, las barras de desplazamiento no se muestren.
• Auto: en este caso, la presencia de las barras depende del contenido. Si éste sobre-
pasa las dimensiones propuestas por el ScrollViewer, las barras de desplazamientos
se mostrarán de manera automática. De esta forma pueden estar visibles o no.
• Hidden: en este caso, la barra de desplazamiento no se mostrará, pero el conteni-
do creado dentro del control ScrollViewer que exceda el tamaño del contenedor
tampoco será visible. Esta propiedad es útil cuando queramos sincronizar dos
4. XAML AL EXTREMO
98
04_Silverlight.qxp 9/30/09 1:31 PM Page 98
ScrollViewer, ocultando las barras de desplazamiento de uno y dejando que la
interacción del usuario con el segundo ScrollViewer impacte en el primero con
barras de desplazamiento escondidas.
• Visible: esta propiedad indica que las barras de desplazamiento se mostrarán, in-
cluso, si el contenido del control ScrollViewer no excede su tamaño.
Podemos ver, en el siguiente código, cómo configurar las barras de desplazamiento:
ScrollViewer x:Name=”[NombreDelControl]”
HorizontalScrollBarVisibility=”[Disabled | Auto | Hidden | Visible]”
VerticalScrollBarVisibility=”[Disabled | Auto | Hidden | Visible]”
/ScrollViewer
La siguiente figura, muestra cómo se han implementado dos controles ScrollViewer,
los cuales han sido sincronizados para que, sobre la base del contenido del segun-
do, el primero se desplace y presente el mismo estado. Cada control ScrollViewer
se encuentra en una celda de una grilla y, a su vez, cada ScrollViewer posee un con-
trol StackPanel para contener otros controles.
Figura 12. Dos ScrollViewer sincronizados.
A continuación, podemos ver el código XAML que da vida a la figura anterior:
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
Controles y componentes
99
04_Silverlight.qxp 9/30/09 1:31 PM Page 99
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition Width=”100”/
ColumnDefinition Width=”150”/
ColumnDefinition/
/Grid.ColumnDefinitions
Button Content=”Crear elementos” VerticalAlignment=”Top”
Click=”Button_Click”/
ScrollViewer x:Name=”Scroll1” Grid.Column=”1”
HorizontalScrollBarVisibility=”Visible”
VerticalScrollBarVisibility=”Hidden”
StackPanel x:Name=”MiStackPanel”
/StackPanel
/ScrollViewer
ScrollViewer x:Name=”Scroll2” Grid.Column=”2”
HorizontalScrollBarVisibility=”Visible”
VerticalScrollBarVisibility=”Visible”
LayoutUpdated=”Scroll2_LayoutUpdated”
StackPanel x:Name=”SegundoStackPanel”
/StackPanel
/ScrollViewer
/Grid
Notemos que tanto al botón como a uno de los controles ScrollViewer se les han
agregado eventos. En el caso del botón, el código creará controles de manera di-
námica para ser agregados a los controles StackPanel que están contenidos por
los ScrollViewer. En el caso del control ScrollViewer, el evento actualizará la po-
sición de las barras de desplazamiento del primer ScrollViewer cada vez que éste
se actualice. Podemos ver el código C# a continuación:
private void Button_Click(object sender, RoutedEventArgs e)
{
TextBox textBox = new TextBox();
textBox.Text = “Nuevo control”;
this.MiStackPanel.Children.Add(textBox);
TextBox textBox2 = new TextBox();
textBox2.Text = “Nuevo TextBlock representando el TextBox”;
4. XAML AL EXTREMO
100
04_Silverlight.qxp 9/30/09 1:31 PM Page 100
this.SegundoStackPanel.Children.Add(textBox2);
}
private void Scroll2_LayoutUpdated(object sender, EventArgs e)
{
this.Scroll1.ScrollToVerticalOffset(this.Scroll2.VerticalOffset);
}
Como vemos en la Figura 13, al agregar controles de manera dinámica, el control
ScrollViewer de la derecha muestra una barra de desplazamiento vertical, pero el
otro ScrollViewer no presenta barra de desplazamiento alguna a pesar de tener
tantos elementos como el de la derecha. Al mover la barra de desplazamiento del
ScrollViewer de la derecha, también se desplaza el otro.
Figura 13. A pesar de que uno contiene
barras de desplazamiento visibles y el otro no, ambos
ScrollViewer están sincronizados.
Control Border
El control Border es el más simple de los controles, aunque puede resultar extre-
madamente útil. Como su nombre en inglés lo indica, el control Border (borde o
contorno) marca un borde a lo que contiene. Ya lo hemos usado en el capítulo 2 al
crear un contorno para la película en nuestro visor de videos. De cualquier mane-
ra, este control posee otros atributos que resultan útiles. Es posible asignarle un
grosor a cada lado del borde, así como crear esquinas redondeadas. A continua-
ción podemos ver la declaración de un control Border:
Controles y componentes
101
04_Silverlight.qxp 9/30/09 1:31 PM Page 101
Border x:Name=”[NombreDelControl]”
/Border
Para asignar los valores al borde, usamos el atributo BorderThickness, empleando un
valor numérico en pixeles correspondiente al borde izquierdo, superior, derecho e in-
ferior, en ese orden, separado por comas. El atributo CornerRadius especifica el radio
numérico de curvatura de las esquinas pudiendo determinar los valores para la esqui-
na superior izquierda, superior derecha, inferior derecha e inferior izquierda, separados
por comas. Veamos, a continuación, un control Border configurado:
Border BorderThickness=”5,5,5,5” BorderBrush=”#FFA76666”
CornerRadius=”10,10,0,0”
/Border
Figura 14. Control Border configurado con grosor
de 5 pixeles y redondeado en las esquinas superiores.
4. XAML AL EXTREMO
102
,
Los símbolos de corchetes usados en el código de ejemplo representan elementos que deben
ser reemplazados en el momento de la escritura del código real. Debemos cambiar estos valo-
res por aquellos que sean convenientes para la aplicación que estemos realizando.
SÍMBOLO DE CORCHETE
04_Silverlight.qxp 9/30/09 1:31 PM Page 102
Controles de interacción con el usuario
Los controles que veremos listados a continuación son aquellos que presentan la
posibilidad de interactuar con el usuario, en especial, para capturar datos y ac-
ciones que éste realice o para presentarle información. Como podemos imaginar,
son los controles más utilizados en cualquier interfaz.
Control Button
El control Button o botón es uno de los más conocidos y, prácticamente, lo en-
contramos en todas las interfaces visuales. Posee como objetivo principal el de
disparar acciones por parte del usuario. Su declaración es intuitiva, como po-
demos ver en el código que aparece a continuación:
Button x:Name=”[NombreDelControl]” Content=”[Texto del Botón]”
/Button
El atributo Content hace referencia al texto que se mostrará en el interior del con-
trol. La función primordial del control Button es la de poder capturar el clic del
mouse y así disparar un evento para que nuestra pieza de código reaccione a éste.
Podremos enlazar este evento a nuestro código agregando el atributo Click a la
descripción del control más el nombre de la función en nuestro código C# que se
utilizará para ejecutar el evento en cuestión.
Button x:Name=”[NombreDelControl]” Content=”[Texto del Botón]”
Click=”[NombreDeFuncion]” 
/Button
La función por utilizar debe seguir una firma o contener una serie de parámetros
exactos; sin esta firma, el evento no podrá ser enlazado en forma correcta.
private void [NombreDeFuncion](object sender, RoutedEventArgs e)
El elemento sender de tipo object contiene el objeto ejecutor del evento. Este
parámetro es importante, ya que podríamos tener asociados a la misma función
diferentes eventos Click de distintos botones. En el siguiente código, se crean tres
controles del tipo Button desde nuestro código, asociando cada uno de ellos a la
misma función creada con anterioridad. Cada vez que se dispare el evento de
cualquiera de los botones, se tomará ese texto, haciendo uso del objeto sender, para
informar qué botón realizó la acción. Primero declaramos el código XAML:
Controles y componentes
103
04_Silverlight.qxp 9/30/09 1:31 PM Page 103
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition Width=”0.332*”/
ColumnDefinition Width=”0.51*”/
ColumnDefinition Width=”0.158*”/
/Grid.ColumnDefinitions
StackPanel x:Name=”MiStackPanel”
Button Click=”Button_Click” Content=”Botón XAML”
HorizontalContentAlignment=”Center”/
/StackPanel
TextBlock x:Name=”mensaje” HorizontalAlignment=”Stretch”
Margin=”8,8,0,0” VerticalAlignment=”Stretch” Grid.Column=”1” Text=””
TextWrapping=”Wrap”/
/Grid
Luego, el código que generará los botones y enlazará los eventos:
public partial class Page : UserControl
{
public Page()
{
InitializeComponent()
CrearBotones();
}
private void CrearBotones()
{
for (int i = 0; i  3; i++)
{
Button boton = new Button();
boton.Click += new RoutedEventHandler(Button_Click);
boton.Content = “Botón “ + i.ToString();
this.MiStackPanel.Children.Add(boton);
}
}
4. XAML AL EXTREMO
104
04_Silverlight.qxp 9/30/09 1:31 PM Page 104
private void Button_Click(object sender, RoutedEventArgs e)
{
this.mensaje.Text = “Presionado: “ + ((Button)sender).Content;
}
}
Cada uno de los botones creado en la función CrearBotones() es adicionado a un
control StackPanel, además de asociar el evento Click a la función Button_Click().
En la siguiente figura, podemos ver cómo se han creado los botones y también
el resultado que se muestra cuando se presiona cada botón.
Figura 15. Lista de controles creados en forma dinámica con eventos asociados.
El control Button también posee la capacidad de incluir, dentro de él, otros con-
troles. Éste es el caso en el cual podemos redefinir su formato por medio de un
control Image. Si lo colocamos dentro del tag del control Button, podremos ha-
cer que la cara visible sea igual a la imagen seleccionada.
Controles y componentes
105
RRR
Cuando trabajamos con contenedores, debemos tener en cuenta que es posible colocar sólo un con-
tenedor por página Silverlight. Si bien se pueden anidar controles del tipo contenedor, solamente
debe existir uno a nivel general, es decir, ubicado entre los tags UserControl/UserControl.
CONTENEDORES
04_Silverlight.qxp 9/30/09 1:31 PM Page 105
Button x:Name=”[NombreDelControl]”
Image Height=”[Alto en píxeles]” Width=”[Ancho en píxeles]”
Source=”[Nombre de la imágen]”/
/Button
En la siguiente figura, es posible ver el nuevo botón usando una imagen como
cara visible. Cabe destacar que el comportamiento de eventos en el botón será
exactamente igual que un botón sin otro elemento anidado.
Figura 16. Un botón anidando una imagen.
Control CheckBox
Este control, conocido también como de casilla de verificación, presenta, típica-
mente, un cuadrado donde el usuario puede marcar o desmarcar la casilla. Para de-
clarar un control CheckBox, podremos hacerlo de la siguiente forma:
CheckBox x:Name=”[NombreDelControl]” Content=”[Texto del CheckBox]”
/CheckBox
En este caso, el atributo Content mostrará el texto escrito al margen derecho de la
casilla de verificación. Este control posee los dos estados comunes para este tipo
de controles, que pueden variar entre verificado y no verificado. Pero también es
posible obtener con él un tercer estado para casos donde se requiera un estado
parcialmente verificado o indeterminado. Para lograr esto, tendremos que hacer
uso del atributo IsThreeState, colocando como valor True (verdadero).
4. XAML AL EXTREMO
106
04_Silverlight.qxp 9/30/09 1:31 PM Page 106
CheckBox
Content=”C#” IsThreeState=”True”
HorizontalContentAlignment=”Left”/
También es posible especificar que el control esté en estado verificado por defecto,
haciendo uso del atributo IsChecked con su valor igual a True.
CheckBox
Content=”C#” IsChecked=”True”
HorizontalContentAlignment=”Left”/
En la figura que aparece a continuación, se muestra cómo los controles CheckBox
presentan el comportamiento configurado en cada caso.
Figura 17. Un control CheckBox por cada opción disponible.
Este control puede poseer cuatro eventos para disparar por cada uno de los estados.
• Click: este evento es disparado cuando el usuario presiona el control CheckBox
con el botón del mouse.
• Checked: sólo se disparará cuando el control pase al estado de verificado.
• Unchecked: en este caso, el evento será ejecutado sólo cuando el control pase
de cualquier estado a no verificado.
• Indeterminate: si hemos configurado el atributo IsThreeState a verdadero, este
evento se disparará cuando el control entre en el tercer estado de selección.
Controles y componentes
107
04_Silverlight.qxp 9/30/09 1:31 PM Page 107
El siguiente código XAML muestra todas las configuraciones posibles. En este
caso, se han configurado eventos para el segundo control CheckBox:
Grid x:Name=”LayoutRoot” Background=”White”
StackPanel HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”
TextBlock Text=”¿En qué lenguaje programas?”
TextWrapping=”Wrap”/
CheckBox
Content=”C#” IsChecked=”True”
HorizontalContentAlignment=”Left”/
CheckBox
Content=”Visual Basic.Net” IsThreeState=”True”
HorizontalContentAlignment=”Left” Click=”CheckBox_Click”
Checked=”CheckBox_Checked”
Indeterminate=”CheckBox_Indeterminate”
Unchecked=”CheckBox_Unchecked”/
CheckBox
Content=”Java” IsThreeState=”True”
HorizontalContentAlignment=”Left”/
TextBlock Text=”” TextWrapping=”Wrap” x:Name=”mensaje”/
/StackPanel
/Grid
Para capturar los eventos, deberemos escribir el siguiente código C#:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
}
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
this.mensaje.Text = “Usted usa Visual Basic.net”;
}
private void CheckBox_Indeterminate(object sender, RoutedEventArgs e)
{
this.mensaje.Text = “No está seguro si usa o no Visual Basic.net”;
}
4. XAML AL EXTREMO
108
04_Silverlight.qxp 9/30/09 1:31 PM Page 108
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
this.mensaje.Text = “Usted no usa Visual Basic.net”;
}
En el código anterior, no hemos colocado líneas adicionales en el evento Click debido
a que éste se disparará en todas las oportunidades que el usuario presione el control, sin
importar el estado al cual pasará en cada clic. El resultado debería ser el siguiente:
Figura 18. Al pasar al estado indeterminado,
es desplegado el mensaje correspondiente.
Si bien podemos usar los eventos para recuperar información de los controles,
existirán casos donde estos eventos no sean necesarios, pero sí conocer el estado
de los controles por medio de nuestro código. Para poder acceder al control, es
necesario asignarle un nombre descriptivo.
CheckBox
Content=”Visual Basic.Net” IsThreeState=”True”
HorizontalContentAlignment=”Left” Click=”CheckBox_Click”
Checked=”CheckBox_Checked” Indeterminate=”CheckBox_Indeterminate”
Unchecked=”CheckBox_Unchecked” x:Name=”VBCheckBox”/
Una vez nombrado el control, podremos usar la propiedad IsChecked para accede al
valor actual del elemento. Esta propiedad es un valor del tipo Verdadero/Falso que,
además, cuenta con el atributo Nulleable, lo que significa que puede mantener tres
Controles y componentes
109
04_Silverlight.qxp 9/30/09 1:31 PM Page 109
estados, True (verdadero), False (falso) y Null (nulo). Estos tres valores representan
los tres posibles estados del control, siendo verdadero para el estado verificado,
falso para no verificado y nulo para indeterminado. Como se observa a continua-
ción, el estado del control CheckBox se escribe en la consola de depuración.
System.Diagnostics.Debug.WriteLine(“CheckBox verificado: “ +
this.VBCheckBox.IsChecked.ToString());
Control RadioButton
El control RadioButton extiende la funcionalidad del control CheckBox antes visto.
Si bien éste se presenta como una casilla de verificación, el formato visual tradicional
es de un círculo, donde puede ser seleccionado uno de éstos en un grupo de con-
troles similares. El control RadioButton tiene el objetivo de presentar opciones de
manera grupal, donde el usuario pueda seleccionar una de ese grupo, a diferencia
del CheckBox, donde el usuario puede seleccionar tantas opciones como crea con-
veniente. Podemos declarar un control RadioButton de la siguiente forma:
RadioButton x:Name=”[NombreDelControl]” Content=”[Texto del RadioButton]”
/RadioButton
Como hemos dicho, el objetivo de este control es el trabajo en conjunto con otros
similares de manera grupal. Para lograr este efecto, es necesario especificar, para cada
control RadioButton, el nombre del grupo al cual pertenece. Todos los controles
RadioButton con el mismo grupo actuarán como una unidad, pasando del estado
verificado a no verificado en forma automática. Para configurar un grupo, debere-
mos usar el atributo GroupName, colocando el nombre del grupo correspondiente.
Grid x:Name=”LayoutRoot” Background=”White”
StackPanel
TextBlock Text=”Género:”/TextBlock
RadioButton Content=”Masculino” GroupName=”Sexo”/
RadioButton Content=”Femenido” GroupName=”Sexo”/
/StackPanel
/Grid
El código anterior muestra cómo podemos agrupar dos controles RadioButton me-
diante el atributo GroupName. Si colocamos los dos controles dentro del mismo grupo,
obtendremos el resultado de la figura en la página siguiente.
4. XAML AL EXTREMO
110
04_Silverlight.qxp 9/30/09 1:31 PM Page 110
Figura 19. Controles RadioButton en un mismo grupo.
Es posible generar tantos grupos cono necesitemos. Cada conjunto de controles
RadioButton trabajará de manera independiente. El siguiente código extiende el
anterior, agregando dos columnas a la grilla y generando un nuevo grupo de con-
troles RadioButton en la segunda columna:
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
StackPanel
TextBlock Text=”Género:”/TextBlock
RadioButton Content=”Masculino” GroupName=”Sexo”/
RadioButton Content=”Femenido” GroupName=”Sexo”/
/StackPanel
StackPanel Grid.Column=”1”
TextBlock Text=”Edad:”/
RadioButton Content=”Menor de 18 años” GroupName=”Edad”/
RadioButton Content=”Mayor de 18 años” GroupName=”Edad”/
/StackPanel
/Grid
Controles y componentes
111
04_Silverlight.qxp 9/30/09 1:31 PM Page 111
De esta forma, tenemos dos grupos, uno definido por el valor Sexo y otro por Edad.
Al seleccionar cualquiera de los elementos de un grupo, éstos trabajarán de ma-
nera independiente o en relación con su grupo.
Figura 20. Dos grupos de RadioButton
trabajando de manera independiente.
El control RadioButton, al igual que el control CheckBox, puede mostrarse verifi-
cado desde el inicio mediante el atributo IsChecked, configurando su valor a True
(verdadero), como vemos a continuación:
RadioButton Content=”Mayor de 18 años” GroupName=”Edad”
IsChecked=”true”/
Este control posee eventos similares al del control CheckBox. Es posible enlazar
eventos a la acción de presionado del mouse y al cambio de su estado. Como las
posibilidades del control RadioButton son más limitadas que las del control CheckBox,
4. XAML AL EXTREMO
112
Dentro de la librería de recursos provista por Microsoft en la Web, podremos encontrar una
sección que hace referencia a la aplicación de reglas, recomendaciones y otros elementos re-
lacionados con el momento del desarrollo de aplicaciones para Windows. Para poder ingresar
en este sitio, deberemos navegar a la siguiente dirección: http://msdn.microsoft.com/.
APRENDIENDO SOBRE UX
04_Silverlight.qxp 9/30/09 1:31 PM Page 112
consideremos que no vamos a tener disponible el evento Indeterminate, así co-
mo la propiedad que da vida a esta capacidad. Podemos ver un ejemplo de los
eventos disponibles para este control a continuación:
RadioButton Content=”Mayor de 18 años” GroupName=”Edad”
IsChecked=”true” Click=”RadioButton_Click”
Checked=”RadioButton_Checked” x:Name=”RadioButtonMayor18”/
El enlace de estos eventos en nuestro código C#.
private void RadioButton_Click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(“Mayor de 18 años presionado”);
}
private void RadioButton_Checked(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(“Estado del control: “ +
this.RadioButtonMayor18.IsChecked.ToString());
}
Control HyperlinkButton
El control HyperlinkButton es uno de los controles más simples de manipular. Su
objetivo consiste en proveer de un enlace o vínculo para navegar desde nuestra apli-
cación hacia otra dirección web. Teniendo en cuenta que las aplicaciones Silverlight
son hospedadas por los navegadores web en un ambiente web, este control resulta
fundamental en cualquier proyecto que llevemos a cabo. Cuenta con dos atributos
primarios: Content, como en controles anteriores, es usado para desplegar el texto
que mostrará el control; y NavigateUri contiene el valor de la URL o página adon-
de el navegador web se dirigirá. A continuación, veamos un ejemplo:
Controles y componentes
113
RRR
Un cambio significativo en los lenguajes de programación basados en Microsoft.Net fue la in-
corporación de un nuevo estado para los tipos de datos. Este tipo se denomina Nulleable, o tipo
de dato con soporte de nulos, y hace que el dato nulo también sea considerado un valor.
ESTADOS DE LAS VARIABLES
04_Silverlight.qxp 9/30/09 1:31 PM Page 113
HyperlinkButton Content=”Ir a RedUsers”
NavigateUri=”http://www.redusers.com”
/HyperlinkButton
Control Image
El control Image presenta un comportamiento particular. Si bien es utilizado pa-
ra desplegar imágenes en nuestras aplicaciones Silverlight, este control nos per-
mite visualizar imágenes que estén contenidas tanto en nuestra aplicación como
en cualquier otra dirección web válida. La diferencia de estas dos posibilidades
radica en el tamaño del archivo generado por nuestra aplicación y qué cantidad de
información estaremos dispuestos a transferir al cliente que la consuma. Pensemos
que las imágenes adicionadas a nuestros proyectos Silverlight son empaquetadas
dentro del archivo de aplicación de Silverlight, y éste debe ser descargado por
completo antes de poder ejecutarse. Como vemos en la figura que aparece deba-
jo, el archivo logo.jpg es incluido en el proyecto para luego ser visualizado por el
control Image desde el mismo archivo.
Figura 21. Podemos ver la imagen incluida
en el proyecto, a la derecha, en el explorador de soluciones.
Al compilar el proyecto, Visual Studio 2008 generará un archivo que tendrá la
extensión XAP (eXtended Application Package). Este archivo es el resultado de
nuestro proyecto, tanto del código como de todas las imágenes incluidas dentro
de él, por lo que, mientras más imágenes agreguemos, este archivo crecerá en ta-
maño y, por ende, se deberá descargar un archivo mayor en el cliente, que hará
más lenta la ejecución inicial de la aplicación.
4. XAML AL EXTREMO
114
04_Silverlight.qxp 9/30/09 1:31 PM Page 114
Figura 22. Archivo XAP creado en la compilación de la aplicación Silverlight.
Por lo dicho antes, es necesario encontrar un balance entre los archivos de imá-
genes que vamos a incluir dentro del proyecto y aquellos que deberemos consumir
de manera dinámica desde otro recurso de red. Para declarar un control Image,
podemos hacerlo con el siguiente código:
Image Source=”[Nombre de la imagen | Ruta de acceso de la
imagen]”/Image
Si agregamos la imagen a nuestra solución, con sólo colocar su nombre, podre-
mos visualizarla dentro del control Image. Por el contrario, colocando la direc-
ción web completa de la imagen por visualizar, el control Image la consumirá
desde su origen. Veamos ejemplos de ambas formas:
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
/Grid.ColumnDefinitions
Controles y componentes
115
04_Silverlight.qxp 9/30/09 1:31 PM Page 115
Image Source=”logo.jpg”/Image
Image Source=”http://www.redusers.com/wp-
content/themes/redusers/images/logo.jpg” Grid.Row=”1”/Image
/Grid
En el código anterior, hemos colocado dos controles Image, uno que utiliza una ima-
gen incluida en el mismo proyecto Silverlight y la segunda que consume la misma
imagen desde su origen web. En la siguiente figura, podemos ver el resultado.
Figura 23. Arriba, la imagen tomada desde
la solución. Abajo, consumida desde su dirección web.
Este control también cuenta con un atributo llamado Stretch, que es utilizado para
configurar el comportamiento de la imagen sobre la base del tamaño elegido para
el control Image. Los valores del atributo Stretch pueden ser los siguientes:
• None: este atributo no aplicará ningún cambio a la imagen contenida por el con-
trol Image y la mostrará en su tamaño original, incluso, cortando partes de ésta si
es más grande que su contenedor.
• Fill: sin importar el tamaño original de la imagen, ésta se ajustará al contenedor
Image para ocupar o rellenar por completo el tamaño del control. Esto puede cau-
sar la deformación de la imagen.
• Uniform: al igual que Fill, esta propiedad rellenará todo el contenedor con la ima-
gen, pero ajustándola sin deformarla.
• UniformToFill: este valor es la conjunción de los dos anteriores. Ajusta la imagen
para que llene por completo el contenedor sin deformarla.
4. XAML AL EXTREMO
116
04_Silverlight.qxp 9/30/09 1:31 PM Page 116
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
Image Source=”logo.jpg” Stretch=”None”/Image
Image Source=”http://www.redusers.com/wp-
content/themes/redusers/images/logo.jpg” Grid.Row=”1”
Stretch=”Fill”/Image
Image Source=”logo.jpg” Grid.Column=”1”/
Image Source=”logo.jpg” Grid.Column=”1” Grid.Row=”1”
Stretch=”UniformToFill”/
/Grid
Figura 24. Aplicando los cuatro modificadores posibles para el control Image.
Control ComboBox
El objetivo del control ComboBox es el de brindarle al usuario la posibilidad de elegir
un elemento de entre un conjunto de elementos o lista de éstos. Como todos los con-
troles comúnmente usados en el desarrollo de software, entre sus objetivos está el de
optimizar las interfaces gráficas para brindar una mejor experiencia al usuario. Parte
de esta optimización radica en la capacidad de reducir los elementos o controles
Controles y componentes
117
04_Silverlight.qxp 9/30/09 1:31 PM Page 117
presentados en pantalla tratando de no sobrecargar, en lo visual, al usuario. El control
ComboBox puede presentar una gran cantidad de información en un espacio reducido.
La declaración del control ComboBox podemos verla a continuación:
ComboBox x:Name=”[NombreDelControl]”
/ComboBox
Como el ComboBox representa una lista de elementos entre los que se debe elegir
alguno, es necesario que agreguemos tantos elementos como necesitemos mostrar,
entre los cuales el usuario seleccionará. Para hacer esto, deberemos incluir el tag
ComboBoxItem dentro del tag representativo del control ComboBox.
ComboBox VerticalAlignment=”Top” Margin=”0,0,165,0” Height=”38”
Grid.Row=”1”
ComboBoxItem Content=”Item 1”/ComboBoxItem
ComboBoxItem Content=”Item 2”/ComboBoxItem
ComboBoxItem Content=”Item 3”/ComboBoxItem
ComboBoxItem Content=”Item 4”/ComboBoxItem
ComboBoxItem Content=”Item 5”/ComboBoxItem
/ComboBox
El código anterior genera un control ComboBox con cinco elementos, que se mostrarán
en una lista desplegable al momento de presionar sobre la flecha derecha del control.
Figura 25. ComboBox desplegado para seleccionar uno de los ítems de la lista.
4. XAML AL EXTREMO
118
04_Silverlight.qxp 9/30/09 1:31 PM Page 118
Una vez seleccionado un ítem de la lista, es posible saber cuál de los elementos lista-
dos es el que fue seleccionado. Esto es útil para recolectar los valores elegidos por el
usuario en la aplicación. Para comprobar cuál ha sido el elemento marcado, prime-
ro deberemos asignarle un nombre al control ComboBox ya que, de esta forma, lo ac-
cederemos desde nuestro código. El siguiente código XAML muestra cómo hacerlo:
ComboBox x:Name=”ComboBox1” VerticalAlignment=”Top” Margin=”0,0,165,0”
Height=”38” Grid.Row=”1”
ComboBoxItem Content=”Item 1”/ComboBoxItem
ComboBoxItem Content=”Item 2”/ComboBoxItem
ComboBoxItem Content=”Item 3”/ComboBoxItem
ComboBoxItem Content=”Item 4”/ComboBoxItem
ComboBoxItem Content=”Item 5”/ComboBoxItem
/ComboBox
TextBlock x:Name=”mensaje” HorizontalAlignment=”Left”
VerticalAlignment=”Top” TextWrapping=”Wrap” Grid.Row=”1”
Margin=”0,42,0,0”/
Button HorizontalAlignment=”Right” Click=”Button_Click”
VerticalAlignment=”Top” Content=”Aceptar” Grid.Row=”1”
Margin=”0,0,84.808,0” Height=”38” Width=”76”/
También hemos agregado un control Button y un control TextBlock, el mismo que
hemos usado en otros ejemplos y del que hablaremos un poco más adelante. Una vez
hecho esto, pasaremos al código C#, donde colocaremos la lógica que captura esta
información dentro del método disparado por el evento Click del botón.
private void Button_Click(object sender, RoutedEventArgs e)
{
this.mensaje.Text =
((ComboBoxItem)this.ComboBox1.SelectedItem).Content.ToString();
}
Por medio de la propiedad SelectedItem del control ComboBox, es posible obtener un
objeto del tipo Object. Este objeto es la representación del tipo de elemento seleccio-
nado. En el código de este ejemplo, habíamos utilizado un elemento ComboBoxItem
como tipo de objeto para cada ítem del ComboBox. Por este motivo, el objeto devuelto
por la propiedad SelectedItem será, internamente, de este tipo, razón por la cual reali-
zamos un Cast (Conversión) del tipo Object a un tipo ComboBoxItem, accediendo por
último a la propiedad Content, que almacena el valor de este elemento.
Controles y componentes
119
04_Silverlight.qxp 9/30/09 1:31 PM Page 119
Figura 26. Una vez seleccionado el elemento,
el valor de éste es mostrado en el control TextBlock.
Si bien podemos agregar ítems por medio de la escritura de XAML como en el ejem-
plo anterior, es posible adicionar nuevos elementos desde nuestro código. De la mis-
ma forma que con XAML, necesitamos crear un nuevo elemento ComboBoxItem,
configurando sus propiedades y adicionándolo, en definitiva, al control ComboBox.
A continuación, vemos cómo hacerlo:
public void CargarCombo()
{
for (int i = 0; i  10; i++)
{
this.ComboPorCodigo.Items.Add(new ComboBoxItem()
{ Content = “Item “ + i.ToString() });
}
}
4. XAML AL EXTREMO
120
,
En el código de ejemplo, el símbolo | (Pipe) presenta una condición OR (Uno u otro). Este sím-
bolo representa la posibilidad de elegir para las propiedades una u otra de las listadas. Como
existen propiedades con más de dos valores seleccionables, éstos se encontrarán delimitados
por tantos | como valores contenga.
SÍMBOLO PIPE
04_Silverlight.qxp 9/30/09 1:31 PM Page 120
El código creará diez elementos ComboBoxItem, adicionándolos al control ComboBox.
Podemos ver el resultado del despliegue de la lista de elementos en la siguiente imagen:
Figura 27. ComboBox desplegado con elementos creados en forma dinámica.
Contamos con una tercera forma de crear elementos para un control ComboBox. Es-
ta forma es la de enlazado de datos. El enlazado de datos nos facilita la tarea de
crear elementos por nuestra cuenta, al mismo tiempo que estos datos podrían ser
obtenidos al ejecutar una consulta a una base de datos, servicio web o cualquier otro
que pudiera retornar una colección de elementos.
public void CargarComboEnlazado()
{
Liststring datos = new Liststring();
for (int i = 0; i  10; i++)
{
datos.Add(“Item “ + i.ToString());
}
this.ComboEnlazado.ItemsSource = datos;
}
En este ejemplo simple, en lugar de cargar directamente los elementos sobre el
ComboBox por cada iteración del ciclo, simulamos una colección de datos por
medio de una lista genérica, asignando esta lista a la propiedad ItemsSource del
control ComboBox. Esta asignación disparará el llenado del control con sus ele-
mentos, pudiendo manipularlos como vemos en la siguiente figura.
Controles y componentes
121
04_Silverlight.qxp 9/30/09 1:31 PM Page 121
Figura 28. El control ComboBox desplegado
fue cargado por medio del enlazado de datos.
Como en otros controles, el ComboBox posee una serie de eventos para poder cap-
turar determinadas acciones del usuario y disparar código C#. Algunos de los prin-
cipales eventos los encontramos en la siguiente lista:
• DropDownOpened: este evento es disparado cuando el usuario despliega la lista
con todos los elementos posibles de selección. Puede resultar muy útil para la
carga de datos realizada de manera asíncrona, haciéndola sólo en el momento
en el que la lista desplegable es mostrada.
• DropDownClosed: este evento representa la acción inversa al DropDownOpened. Una
vez el usuario seleccione un elemento y la lista se cierre, este evento será disparado.
• SelectionChanged: cada vez que el usuario selecciona un nuevo elemento de la lis-
ta, éste pasa a ser el elemento seleccionado, cambiando de estado la selección, así
como los índices utilizados. Este evento es útil cuando necesitamos cargar ele-
mentos sobre la base de la selección de un ítem específico.
Para incluir el manejo de los eventos, podemos modificar el ComboBox como vemos
en el código que aparece a continuación
ComboBox x:Name=”ComboEnlazado”
DropDownClosed=”ComboEnlazado_DropDownClosed”
DropDownOpened=”ComboEnlazado_DropDownOpened”
SelectionChanged=”ComboEnlazado_SelectionChanged”
/
4. XAML AL EXTREMO
122
04_Silverlight.qxp 9/30/09 1:31 PM Page 122
Cada método definido en el código XAML también deberá estar presente en
nuestro código C#. Este código mostrará los diferentes mensajes basados en la
acción aplicada en el control ComboBox. Veamos:
private void ComboEnlazado_DropDownClosed(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(“Lista desplegable cerrada”);
}
private void ComboEnlazado_DropDownOpened(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(“Lista desplegable abierta”);
}
private void ComboEnlazado_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(“Nuevo elemento seleccionado”);
}
En todo caso, el control ComboBox no se limita a las características que ya hemos visto.
Este control es extremadamente versátil, pudiendo adicionar elementos de diferentes
tipos a la lista desplegable. Esto quiere decir que no estamos limitados a mostrar ítems
de sólo texto, sino que tendremos la capacidad de agregar elementos complejos como
controles RadioButton, CheckBox, Image, entre otros. El siguiente código XAML
demuestra cómo es posible agregar otro tipo de elementos al control ComboBox:
ComboBox
ListBoxItem Content=”Item 1”/
CheckBox Content=”Item 2”/
ComboBoxItem Content=”Item 3”/
RadioButton Content=”Item 4”/
Image Source=”http://www.redusers.com/wp-
content/themes/redusers/images/logo.jpg”/
/ComboBox
Como podemos ver en el código anterior, el control ComboBox poseerá varios ele-
mentos, entre los que encontraremos un CheckBox, un RadioButton y un control
Image. En la Figura 29 podemos ver este ComboBox en pleno funcionamiento.
Controles y componentes
123
04_Silverlight.qxp 9/30/09 1:31 PM Page 123
Figura 29. El ComboBox tiene elementos complejos dentro de sus elementos seleccionables.
Al seleccionar el ítem del ComboBox, éste pasará a visualizarse como el elemento se-
leccionado, presentando el mismo comportamiento que otros elementos, con la dife-
rencia de que, al ser un elemento compuesto, éste también poseerá las características
de complejidad del control utilizado. En la Figura 30, el ítem representado por un con-
trol CheckBox también incluye la funcionalidad de utilizar la casilla de verificación.
Figura 30. Un control CheckBox como elemento de un control ComboBox.
Control ListBox
El control ListBox es homónimo del control ComboBox que ya vimos. La diferencia de
este control es su capacidad de mostrar la lista de elementos no en una lista desplega-
4. XAML AL EXTREMO
124
04_Silverlight.qxp 9/30/09 1:31 PM Page 124
ble, sino de manera constante, utilizando una barra de desplazamiento para movernos
a través de la lista. Para crear un control ListBox, usamos la siguiente sintaxis:
ListBox x:Name=”[NombreDelControl]”
/ListBox
Como el control ListBox posee el mismo comportamiento que el ComboBox, es po-
sible incluir los mismos elementos complejos, así como elementos simples dentro
de la lista de ítems por mostrar y posibles de selección.
ListBox VerticalAlignment=”Top” Height=”94”
ListBoxItem Content=”Item 1”/
ListBoxItem Content=”Item 2”/
RadioButton Content=”Masculino” GroupName=”Sexo”/
RadioButton Content=”Femenino” GroupName=”Sexo”/
Image Source=”http://www.redusers.com/wp-
content/themes/redusers/images/logo.jpg”/Image
/ListBox
El código anterior muestra cinco elementos entre los cuales podemos encontrar un
grupo de controles RadioButton y un control Image. El atributo Height (alto) es usa-
do como el condicionante para, además de configurar la altura del control, poder
indicar cuántos elementos deberán ser mostrados en la lista inicial.
Figura 31. ListBox con elementos complejos.
Controles y componentes
125
04_Silverlight.qxp 9/30/09 1:31 PM Page 125
Como hemos comentado, este control podría considerarse una extensión del control
ComboBox, por lo que la forma de manipularlo por código, recolectar el elemento se-
leccionado, cargar nuevos elementos e interactuar con los eventos resulta similar. Úni-
camente encontraremos una diferencia en la cantidad de eventos disponibles. Debido
a que este control no posee una lista desplegable, los dos eventos correspondientes al
accionar de la lista no estarán disponibles para su uso, por lo que sólo podremos usar
el evento SelectionChanged, que se disparará cada vez que se accione un nuevo elemento.
Control TextBlock
El control TextBlock es, sin dudas, el más simple de los controles, incluso más senci-
llo que el control HyperlinkButton visto en páginas anteriores. El control TextBlock
cumple la función de mostrar un texto en nuestra aplicación. Este control es útil en
especial para mostrar textos informativos al usuario, así como para complementarlo
con otros controles o en la creación de nuevos controles que requieran desplegar tex-
tos. La declaración de este control se reduce a las siguientes líneas de código:
TextBlock x:Name=”[NombreDelControl]” Text=”[Texto a visualizar]”
/TextBlock
Necesitaremos de un nombre para poder utilizarlo en nuestro código. Podremos ma-
nipular la información desplegada por este control mediante el atributo Text (texto),
configurándolo en el código XAML o mediante código de forma dinámica. El acce-
so desde nuestro código resulta bastante sencillo, como se muestra a continuación:
public void MostrarMensaje()
{
this.MiTextBlock.Text = “Mensaje de bienvenida”;
}
El atributo Text usado en el código XAML es el mismo que se transforma en la pro-
piedad Text en nuestro código, el mismo que usaremos para asignar o recolectar valo-
res desde el control. Como todo componente para desplegar textos, es necesario que
posea la capacidad de darle formato a ese texto, permitiendo variar su color, tipo y ta-
maño de fuente, entre otras opciones. En el siguiente ejemplo, adicionamos algunas
propiedades al control TextBlock para cambiar el tamaño, color y tipo de fuente usada.
TextBlock x:Name=”MiTextBlock” Text=”” FontFamily=”Comic Sans MS”
FontSize=”18” FontWeight=”Bold”
4. XAML AL EXTREMO
126
04_Silverlight.qxp 9/30/09 1:31 PM Page 126
TextBlock.Foreground
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FFEEE659”/
GradientStop Color=”#FF1120A2” Offset=”1”/
/LinearGradientBrush
/TextBlock.Foreground
/TextBlock
Para este caso, agregamos los atributos FontFamily, FontSize y FontWeight. Estos atri-
butos son utilizados para configurar el tipo de fuente, su tamaño y sus modificado-
res como, por ejemplo, Bold (negrita), Normal y otros. También hemos agregado
más elementos para modificar el color de la fuente, usando un color degradado
(hablaremos más de este tema en los siguientes capítulos).
Figura 32. TextBlock con un tipo de fuente diferente de la configurada por defecto.
Control TextBox
Al igual que el control anterior, el control TextBox es uno de los más comunes en el de-
sarrollo de aplicaciones, y ya lo hemos usado en varios de los ejemplos a través de los
capítulos de este libro. Este control es el control básico para introducción de texto por
parte del usuario, permitiéndole escribir texto libremente para que sea procesado
por nuestra aplicación. Este control posee una declaración XAML muy simple:
TextBox x:Name=”[NombreDelControl]” Text=”[Texto a visualizar]”
/TextBox
Controles y componentes
127
04_Silverlight.qxp 9/30/09 1:31 PM Page 127
En el control TextBox es posible especificar el comportamiento que tendrá el flujo del
texto escrito. Por ejemplo, si tenemos un control TextBox con un tamaño en alto ma-
yor a más de una línea de texto, es posible usar el atributo TextWrapping para que, cuan-
do el texto llegue al final de la caja de texto, continúe en la siguiente línea. Si omitimos
esta propiedad o colocamos el valor del atributo igual a NoWrap, el texto seguirá su flu-
jo normal y los caracteres más antiguos escritos desaparecerán del rango visual, tenien-
do que desplazarnos con el teclado para poder volver a ver esa información.
TextBox Text=”” TextWrapping=”[Wrap | NoWrap]”
/TextBox
Figura 33. El TextBox superior utiliza la propiedad Wrap y el de abajo usa NoWrap.
También podemos necesitar cajas de texto para introducción de texto extenso. Estas
cajas poseen un tamaño mayor que las de una sola línea y muestran una barra de des-
plazamiento hacia el margen derecho de la caja, permitiéndole al usuario desplazarse
por el texto escrito. Para lograr esto, deberemos agrandar el tamaño de la caja de texto
tanto como creamos necesario y configurar el atributo VerticalScrollBarVisibility con el
valor Visible. Esta acción mostrará la barra de desplazamiento de manera constante, sin
importar si el texto escrito sobrepasa la capacidad de la caja de texto.
TextBox Text=”” AcceptsReturn=”True”
TextWrapping=”Wrap” Margin=”8,8,53,68”
VerticalScrollBarVisibility=”Visible”
/TextBox
4. XAML AL EXTREMO
128
04_Silverlight.qxp 9/30/09 1:31 PM Page 128
Otra propiedad que aparece en el código es AcceptReturn (aceptar retornos de carros).
Este atributo permite que, si el usuario presiona la tecla INTRO o ENTER, el control re-
fleje esta acción y genere saltos de línea. La Figura 34 muestra dos controles TextBox
configurados con las propiedades antes listadas, donde el que se encuentra en la par-
te inferior aplica el atributo TextWrapping con el valor NoWrap, que al utilizarlo en com-
binación con el atributo HorizontalScrollBarVisibility mostrará además una barra de
desplazamiento en la parte inferior del control TextBox, esperando que el usuario pre-
sione la tecla INTRO o ENTER como condición para enviar el texto a la siguiente línea.
Figura 34. Controles TextBox con la posibilidad
de presentar barras de desplazamiento basadas en su contenido.
TextBox Text=”” AcceptsReturn=”True”
TextWrapping=”Wrap” Margin=”8,8,53,68”
HorizontalScrollBarVisibility=”Visible”
VerticalScrollBarVisibility=”Visible”
/TextBox
TextBox Text=”” AcceptsReturn=”True”
Grid.Column=”0” Grid.Row=”1”
TextWrapping=”NoWrap” Margin=”8,8,53,68”
HorizontalScrollBarVisibility=”Visible”
VerticalScrollBarVisibility=”Visible”
/TextBox
La asignación de información a estos controles, en especial los multilíneas, suele
presentar cierta complejidad cuando se trata de manipular, en nuestro código, los
Controles y componentes
129
04_Silverlight.qxp 9/30/09 1:31 PM Page 129
retornos de carro y asignarlos al control. En el código siguiente, se utilizan los carac-
teres de escape de C# para poder lograr este efecto. Como vemos, utiliza el carácter
de escape n para conseguir asignar un retorno de carro en el texto enviado al control:
private void Button_Click(object sender, RoutedEventArgs e)
{
this.TextoMultilinea.Text = “Texto largo multilínea con nretornos de
carro”;
}
Al igual que los demás controles en Silverlight, el control TextBox también posee
eventos que se dispararán bajo determinadas acciones del usuario. El más destaca-
do es el evento TextChanged, que se disparará cada vez que el contenido del control
(su texto) cambie de estado. Podemos declarar el evento de la siguiente manera:
TextBox Margin=”8,58,8,52” x:Name=”TextBoxConEvento”
TextChanged=”TextBox_TextChanged” Grid.Column=”1” Text=””
TextWrapping=”NoWrap”
/TextBox
En el código que hemos propuesto, el evento TextChanged es asociado al método
TextBox_TextChanged del código C#. Este método, entonces, se ejecutará tantas ve-
ces como el texto de la caja de texto se vea afectado por el usuario.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(this.TextBoxConEvento.Text);
}
En este ejemplo, cada vez que el usuario modifique el texto, éste se escribirá en la
consola de depuración de Visual Studio 2008.
Control PasswordBox
PasswordBox es un control que extiende la funcionalidad del control TextBox con el
objetivo de brindarnos la posibilidad de manipular contraseñas en nuestras aplica-
ciones. El control PasswordBox está diseñado para representar todos los caracteres
introducidos por el usuario por medio de una máscara, ocultando lo que éste es-
criba y mostrando cada carácter introducido por medio de un punto de color negro.
4. XAML AL EXTREMO
130
04_Silverlight.qxp 9/30/09 1:31 PM Page 130
Este control es muy útil en aquellas aplicaciones donde el usuario deba introducir
credenciales de validación, ya que éstas no deben ser mostradas a otros usuarios que
pudieran estar mirando su pantalla en el momento de realizar esta acción. A conti-
nuación, podemos ver el código XAML para declarar este control:
PasswordBox x:Name=”[NombreDelControl]” Password=”[Contraseña a
visualizar]”
/PasswordBox
Debido a que el control PasswordBox manejará contraseñas, el atributo de asig-
nación y lectura del texto contenido se cambia por Password (contraseña). Si bien
el carácter mostrado por defecto es el de un círculo negro, es posible modificar
esto mediante el atributo PasswordChar, pudiendo aplicar cualquier otro carác-
ter, que se usará por cada letra o número introducido por el usuario. El código
siguiente muestra cómo configurar este atributo:
PasswordBox PasswordChar=”-” /
/Password
El carácter elegido en el código anterior es el de un signo de resta, por lo que el
control mostrará este elemento en lugar de los círculos de color negro tradicio-
nales, como se observa en la siguiente figura.
Figura 35. Signos de resta en lugar
de círculos en el patrón del control PasswordBox.
Controles y componentes
131
04_Silverlight.qxp 9/30/09 1:31 PM Page 131
El control PasswordBox también posee eventos comunes utilizados por todos los con-
troles, pero, al igual que el control TextBox, PasswordBox tiene un evento en particular
para capturar la modificación del estado del texto escrito en él. El evento en cuestión
es PasswordChanged, y se comporta de igual forma que su homónimo TextChanged del
control TextBox. Declaramos el evento PasswordChanged de la siguiente forma:
PasswordBox PasswordChanged=”PasswordBox_PasswordChanged” PasswordChar=”-”
/PasswordBox
Como mencionamos, para acceder al contenido escrito en el control PasswordBox,
deberemos usar la propiedad Password como vemos en el siguiente ejemplo:
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(this.Password.Password);
}
El código propuesto anteriormente escribirá cada cambio del control en la con-
sola de depuración de Visual Studio 2008.
Control DataGrid
En el capítulo 3, hemos hecho uso del control DataGrid para mostrar información en
forma de filas y columnas. También vimos algunos atributos que permiten al usua-
rio reordenar las columnas del control en tiempo de ejecución, cambiar el tamaño
de las columnas y especificar diferentes colores para las filas mostradas. En este
caso, iremos un poco más lejos, y mostraremos otras características del control.
Primero, recordemos cómo declarar el control DataGrid en XAML.
data:DataGrid
/data:DataGrid
Al agregar el control, podemos notar que Visual Studio sumará la referencia de
System.Windows.Controls.Data a nuestra solución. Además, agregará una referencia
en la cabecera de nuestro archivo para poder usar el control DataGrid.
UserControl xmlns:data=”clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”
4. XAML AL EXTREMO
132
04_Silverlight.qxp 9/30/09 1:31 PM Page 132
Éste es el motivo por el cual usamos data:DataGrid para declarar el control en nues-
tro código. Podemos ver que el atributo xmlns genera una referencia al tipo data,
indicándole desde dónde deberá consumir estos componentes.
Figura 36. En el árbol de la solución (arriba a la derecha), podemos
ver que Visual Studio 2008 agregó la referencia a System.Windows.Controls.Data.
El control DataGrid tiene otras particularidades y, si bien en el ejemplo del capítulo 3
este control creó las columnas sobre la base de los datos, es posible que necesitemos
manipular de diferentes maneras la construcción de estas columnas. Podríamos, por
ejemplo, necesitar que en la edición de una columna específica, ésta se comporte de
una forma particular. También podríamos necesitar inmovilizar una columna para
que ésta no pueda variar su tamaño por más que el usuario así lo quiera. Para estas
acciones, es posible utilizar Templates Columns (columnas plantilla). Estas co-
lumnas permiten personalizar por completo cada columna y adaptarla a nuestras ne-
cesidades. Veamos el siguiente código:
data:DataGrid AutoGenerateColumns=”False” x:Name=”MiDataGrid”
data:DataGrid.Columns
data:DataGridTemplateColumn Header=”Fecha”
data:DataGridTemplateColumn.CellTemplate
DataTemplate
TextBlock Text=”{Binding FechaNacimiento}”/
/DataTemplate
/data:DataGridTemplateColumn.CellTemplate
/data:DataGridTemplateColumn
/data:DataGrid.Columns
/data:DataGrid
Controles y componentes
133
04_Silverlight.qxp 9/30/09 1:31 PM Page 133
4. XAML AL EXTREMO
134
En el código que aparece en la página anterior, podemos ver algunos nuevos tags
usados para definir nuestras columnas. Veamos en detalle cada uno.
• data:DataGrid.Columns: este tag representa el contenedor para todas las colum-
nas que crearemos por nuestra cuenta.
• data:DataGridTemplateColumn: representa una columna tipo plantilla. Sobre
la base de esta plantilla, todas las filas bajo esta columna tendrán el aspecto de-
finido por la plantilla.
• data:DataGridTemplateColumn.CellTemplate: este tag es el que representa el con-
tenido de la celda de la plantilla. En él, podremos colocar otro control Silverlight,
que será usado para representar el dato de la fila en esa columna.
• {Binding Columna}: al momento de asignar una fuente de datos al DataGrid, todos
los elementos que presenten el patrón {Binding} enlazarán los datos desde la fuen-
te de datos y lo asignarán al atributo del control contenido por la plantilla. El nom-
bre seguido de Binding representa el nombre de la columna en la fuente de datos.
Podemos enlazar los datos desde una lista de entidades como la siguiente:
public class Personas
{
public string Nombre
{
get;
set;
}
public string Apellido
{
get;
set;
}
RRR
Los caracteres de escape son códigos especiales para representar elementos que, típicamente,
no se pueden generar en cadenas de texto. Algunos de los caracteres más usados son: n para
retornos de carro;  para agregar una barra invertida; ” para agregar una comilla doble; ’ pa-
ra agregar una comilla simple.
CARACTERES DE ESCAPE
04_Silverlight.qxp 9/30/09 1:31 PM Page 134
public DateTime FechaNacimiento
{
get;
set;
}
public bool EnviarRegalo
{
get;
set;
}
}
Podemos notar, en el código anterior, que la propiedad FechaNacimiento es del
tipo DateTime, así como EnviarRegalo es del tipo bool. Esto puede ser importante
conocerlo ya que, según el tipo de datos, podremos utilizar un control Silverlight
específico para representar el valor en el DataGrid. En la Figura 37, observamos cómo,
al enlazar los datos, la única columna mostrada es la definida anteriormente.
Figura 37. DataGrid mostrando una columna creada en forma manual.
Podemos crear y enlazar los datos con el siguiente código.
public Page()
{
Controles y componentes
135
04_Silverlight.qxp 9/30/09 1:31 PM Page 135
InitializeComponent();
LlenarGrilla();
}
private void LlenarGrilla()
{
ListPersonas personas = new ListPersonas();
for (int i = 0; i  10; i++)
{
personas.Add(new Personas() { Nombre = “Nombre” + i.ToString(),
Apellido = “Apellido” + i.ToString(), EnviarRegalo = ((i % 2) ==
0 ? true : false),
FechaNacimiento = DateTime.Now.AddDays(i)});
}
this.MiDataGrid.ItemsSource = personas;
}
Para mostrar la propiedad EnviarRegalo de la clase Personas, podríamos, usar un con-
trol CheckBox, asociando el atributo IsChecked al valor de esta propiedad.
data:DataGridTemplateColumn Header=”Regalo”
data:DataGridTemplateColumn.CellTemplate
DataTemplate
CheckBox IsEnabled=”False” IsChecked=”{Binding EnviarRegalo}”
/CheckBox
/DataTemplate
/data:DataGridTemplateColumn.CellTemplate
/data:DataGridTemplateColumn
4. XAML AL EXTREMO
136
RRR
Es importante recordar que, si estamos trabajando con plantillas de columnas, debemos confi-
gurar el atributo AutoGenerateColumns con el valor False para que no se generen las columnas
de forma automática en el momento de enlazar los datos. Si olvidamos esto, las columnas se re-
petirán, y la información no será consistente.
COLUMNAS AUTOMÁTICAS
04_Silverlight.qxp 9/30/09 1:31 PM Page 136
En este caso, la columna representará los valores de la fuente de datos en forma
de control CheckBox como se ve en la figura que aparece a continuación.
Figura 38. En este caso, se ha incorporado una
nueva columna del tipo CheckBox para representar datos.
Así como es posible crear nuestras propias columnas para mostrar la información, tam-
bién podemos crear columnas con comportamiento para el momento de editarlas.
/data:DataGridTemplateColumn.CellTemplate
data:DataGridTemplateColumn.CellEditingTemplate
DataTemplate
basics:DatePicker SelectedDate=”{Binding FechaNacimiento,
Mode=TwoWay}” /
/DataTemplate
/data:DataGridTemplateColumn.CellEditingTemplate
/data:DataGridTemplateColumn
Mediante el código anterior, es posible agregar una plantilla de columna para los
casos en el que el usuario edite el contenido de la celda. También hay que notar
que esta columna data:DataGridTemplateColumn.CellEditingTemplate debe estar
dentro del tag data:DataGridTemplateColumn y dentro del conjunto de la co-
lumna creada para asociar los datos en modo de vista que usamos al principio
del ejemplo. En este caso, la columna de edición es utilizada para mostrar un
control DatePicker y así poder manejar la fecha de nacimiento de una manera
más práctica para el usuario, como se muestra en la Figura 39.
Controles y componentes
137
04_Silverlight.qxp 9/30/09 1:31 PM Page 137
Figura 39. Un control DatePicker como plantilla para la edición de la celda.
Otra característica importante es la de poder congelar columnas para que éstas no se
vean afectadas por barras de desplazamiento. Pensemos en controles DataGrid con gran
cantidad de columnas donde, para poder llegar hasta la última de éstas, es nece-
sario recorrer cada una mediante el uso de barras de desplazamiento. Existirán
ocasiones en las que sea necesario seguir visualizando las primeras columnas por
más que nos desplacemos hasta el final del control DataGrid. Para lograr esto, de-
beremos usar el atributo FrozenColumnCount, asignando la cantidad de columnas
que se van a congelar. Desde nuestro código C#:
this.MiDataGrid.FrozenColumnCount = 1;
Como podemos ver en la Figura 40, la primera columna queda completamente
inmóvil y no se ve afectada por la barra de desplazamiento. Por defecto, cada co-
lumna tomará un tamaño, pero también es posible, mediante código, definir este
comportamiento haciendo que las columnas del control DataGrid se adapten según
diferentes factores por medio del atributo Width de cada columna, asignando co-
mo posibles valores los que vemos a continuación:
• Auto: al usar esta opción, la columna ajustará su tamaño en forma automática.
• SizeToHeader: el tamaño será igual al largo del texto descriptivo de la columna.
• SizeToCells: en este caso, el tamaño de la columna será igual al tamaño máximo
contenido en cualquiera de las celdas de esta columna.
• Valor numérico: colocando sólo un número, la columna será tan ancha como el
valor numérico asignado. Este valor numérico es equivalente a pixeles.
4. XAML AL EXTREMO
138
04_Silverlight.qxp 9/30/09 1:31 PM Page 138
Figura 40. La columna que muestra
la fecha de nacimiento de la persona está inmovilizada.
Control Calendar
El control Calendar nos permite manejar fechas de manera fácil. Por lo general,
el manejo de fechas puede ser una tarea compleja, especialmente cuando necesi-
tamos representar la misma fecha en diferentes idiomas. Para darnos una idea
mediante un ejemplo simple, el patrón DD/MM/YYYY (día, mes, año), utiliza-
do casi siempre en países de habla hispana, difiere del formato MM/DD/YYYY
(mes, día, año), utilizado en países de habla inglesa. Este cambio, que a simple
vista puede resultar trivial, a nivel de código puede ocasionar severos dolores de
cabeza para el desarrollador, ya que implica convertir fechas de un formato a otro
sobre la base de las configuraciones del usuario.
Como podemos imaginar, este problema puede acrecentarse aún más en am-
bientes de aplicaciones orientadas a la Web, debido a que éstas pueden ser acce-
didas desde todos los países del globo, donde cada usuario utiliza un formato de
fechas diferente del nuestro. Imaginemos lo complejo que resultaría tener que
analizar en forma manual cada entrada de un usuario para poder saber la fecha
exacta que quiso introducir. En el código que aparece a continuación vemos la
declaración de un control Calendar en XAML:
basics:Calendar
/basics:Calendar
Es necesario recordar que el prefijo basics: es tomado de la declaración de los con-
troles en la cabecera de nuestro archivo XAML. Esto indica que el control Calendar
Controles y componentes
139
04_Silverlight.qxp 9/30/09 1:31 PM Page 139
también se encuentra incluido en la referencia System.Windows.Controls de las li-
brerías de clases de Microsoft .Net para Silverlight.
UserControl xmlns:basics=”clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls”
El control Calendar posee varios atributos importantes que hacen a su configu-
ración, pudiendo variar la forma de presentar el calendario así como los tipos de
selección de las fechas. Veamos a continuación estos atributos y sus valores.
DisplayMode
Esta propiedad representa la forma en que será mostrado el calendario y sus fechas,
pudiendo optar por alguno de los siguientes valores:
• Month (mes): el calendario muestra todos los días correspondientes al mes selec-
cionado, permitiendo desplazarse de mes en mes y seleccionar uno o más días.
• Year (año): los elementos seleccionables del calendario serán los meses del año ele-
gido, pero no se pueden seleccionar días.
• Decade (década): muestra el calendario en formato de años, desplegando un conjun-
to de años sin meses ni días. Es posible seleccionar un año o un rango de éstos.
Figura 41. Control Calendar con los tres valores
(Year, Decade y Month) posibles para el atributo DisplayMode.
SelectionMode
El atributo SelectionMode (modo de selección) hace referencia a la forma en có-
mo el usuario podrá seleccionar una fecha en el control Calendar. Este atributo
puede tomar los valores que se listan a continuación:
4. XAML AL EXTREMO
140
04_Silverlight.qxp 9/30/09 1:31 PM Page 140
• None: el usuario no podrá seleccionar ninguna fecha del calendario. Esta opción
es ideal para mostrar el calendario para solo lectura.
• SingleDate: el usuario podrá seleccionar una única fecha del calendario.
• SingleRange: con esta opción, el usuario podrá seleccionar un rango de fechas, pe-
ro no podrá concatenarlas con otros rangos o fechas individuales.
• MultiRange: esta selección de múltiples rangos de fechas permite al usuario selec-
cionar rangos de fechas en intervalos. El usuario puede usar la tecla CTRL y el bo-
tón del mouse para seleccionar más de una fecha o un rango de éstas.
Figura 42. En el calendario de la izquierda, podemos
ver cómo se han podido seleccionar múltiples fechas y rangos de fechas.
Según las configuraciones regionales de cada país, es posible que necesitemos
especificar el día que represente el inicio de la semana. Esto podemos lograrlo
mediante el uso del atributo FirstDayOfWeek (primer día de la semana), pudien-
do elegir cualquiera de los días incluidos en la semana mediante su nombre en
inglés: Monday (lunes), Tuesday (martes), Wednesday (miércoles), Thursday (jueves),
Friday (viernes), Saturday (sábado) y Sunday (domingo). El siguiente código apli-
ca los atributos vistos hasta el momento:
basics:Calendar x:Name=”MiCalendario” DisplayMode=”Year”
FirstDayOfWeek=”Monday”
IsTodayHighlighted=”True” SelectionMode=”MultipleRange”
/basics:Calendar
Este control también nos permite definir rangos de fechas que no puedan ser
seleccionadas por el usuario. Esta acción suele ser usada en aplicaciones que ne-
cesiten mostrar días no laborales, fechas disponibles para la selección o fechas ya
Controles y componentes
141
04_Silverlight.qxp 9/30/09 1:31 PM Page 141
seleccionadas que no deban ser utilizadas por el usuario. Para lograr esto, debe-
remos usar la propiedad BlackoutDates y asignar el rango de fechas por bloquear
desde nuestro código C#. En este caso, se mostrará el rango de fechas desde el
6 de junio de 2009 hasta el 15 de junio de 2009 como fechas no seleccionables,
public void ConfigurarCalendario()
{
this.MiCalendario.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2009, 6, 6),
new DateTime(2009, 6, 15)));
}
Figura 43. El calendario de la izquierda muestra
un rango de fechas que no podrán ser seleccionadas.
Es posible agregar tantos rangos de fechas bloqueadas como necesitemos. Para esto será
necesario agregar tantos atributos BlackoutDates como rangos bloqueados necesitemos.
public void ConfigurarCalendario()
{
this.MiCalendario.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2009, 6, 6),
new DateTime(2009, 6, 15)));
this.MiCalendario.BlackoutDates.Add(new CalendarDateRange(
new DateTime(2009, 6, 20),
new DateTime(2009, 6, 28)));
}
4. XAML AL EXTREMO
142
04_Silverlight.qxp 9/30/09 1:31 PM Page 142
El código muestra dos rangos de fechas bloqueadas dejando un pequeño rango
de fechas posibles por seleccionar dentro de este rango.
Figura 44. Podemos ver dos rangos de fechas
bloqueadas en el calendario de la izquierda.
Otra característica del control Calendar es la posibilidad de especificar la fecha por
mostrar, así como acotar el límite de fechas que se van a mostrar a un rango deter-
minado. Esto es útil si necesitamos mostrarle al usuario una fecha específica dife-
rente de la fecha actual o si sólo queremos darle la posibilidad de seleccionar una
fecha dentro de un rango de fechas, pero sin bloquear las no seleccionables, como
vimos antes. Para posicionar el calendario en una fecha específica, deberemos usar,
desde nuestro código C#, la propiedad DisplayDate del calendario, que hará que és-
te se posicione en esa fecha. Los rangos de fechas a los que el usuario tendrá acceso
podremos especificarlos con las propiedades DisplayDateStart y DisplayDateEnd.
this.CalendarioDerecha.DisplayDate = new DateTime(2009, 07, 1);
this.CalendarioDerecha.DisplayDateStart = new DateTime(2009, 07, 1);
this.CalendarioDerecha.DisplayDateEnd = new DateTime(2009, 07, 29);
Controles y componentes
143
RRR
Existe en la Web una infinidad de recursos sobre Silverlight, tanto código de ejemplo como no-
vedades sobre actualizaciones. Uno de los sitios que no podemos dejar de visitar es el de la
biblioteca de clases Microsoft, que podemos encontrar en http://msdn.microsoft.com.
MANTENERSE INFORMADO
04_Silverlight.qxp 9/30/09 1:31 PM Page 143
En el código propuesto, el calendario mostrará como fecha el 1 de julio de 2009,
limitando la selección de fechas a los rangos comprendidos entre la fecha ante-
rior y el 29 de julio de 2009. En la Figura 45, podemos ver cómo este calendario
muestra sólo este rango como única selección posible.
Figura 45. El calendario que se encuentra
a la derecha muestra sólo los valores especificados dentro
del rango de fechas asignadas por código.
Es posible también entregarle al usuario un calendario con fechas ya seleccionadas se-
gún lo que establezcamos desde nuestro código C#. Para esto, debemos usar las pro-
piedades SelectedDate cuando queramos seleccionar una única fecha, y SeletedDates
cuando necesitemos seleccionar una o más fechas. En el código, podemos ver cómo
se seleccionan fechas diferentes para generar una línea de selección como se ve en la
Figura 46, que aparece en la pagina siguiente.
this.MiCalendario.SelectedDate = DateTime.Now.AddDays(10);
this.MiCalendario.SelectedDates.Add(DateTime.Now.AddDays(11));
this.MiCalendario.SelectedDates.Add(DateTime.Now.AddDays(12));
4. XAML AL EXTREMO
144
RRR
Cuando creamos plantillas para las columnas y, además, incluimos plantillas de edición de co-
lumnas, es importante asegurarnos de agregar el atributo Mode con el valor TwoWay (dos vías).
Si no lo hacemos, podríamos perder información, ya que la fuente de datos no se actualizaría con
la acción de edición del usuario.
MODOS EN EDICIÓN
04_Silverlight.qxp 9/30/09 1:31 PM Page 144
Figura 46. Además de las fechas bloqueadas en el calendario
de la izquierda, podemos ver un rango de fechas seleccionadas.
Estas mismas propiedades pueden ser usadas para recolectar la fecha seleccionada.
Teniendo en cuenta que, para asignar el valor hemos usado un tipo DateTime, al
recuperarlo obtendremos también un tipo DateTime. La ventaja de esto es que no
deberemos preocuparnos por el formato de fecha usado por el usuario.
private void Button_Click(object sender, RoutedEventArgs e)
{
this.textoFecha.Text = “Fecha seleccionada: “ +
this.CalendarioDerecha.SelectedDate.ToString();
}
Figura 47. Al presionar el botón, éste muestra
la fecha seleccionada en el calendario de la derecha.
Controles y componentes
145
04_Silverlight.qxp 9/30/09 1:31 PM Page 145
Como utilizamos SelectedDates, pudimos agregar un rango de fechas seleccionadas, por
lo que deberemos utilizar esta misma propiedad para obtener aquellas fechas seleccio-
nadas. Esta propiedad es útil cuando se conjuga con el uso del atributo SelectionMode,
que ya hemos visto, porque, con él, podemos darle al usuario la posibilidad de especi-
ficar más de una fecha; luego, necesitaremos algún mecanismo para poder capturar esas
fechas. El código siguiente no realiza ninguna acción en especial, pero muestra cómo
es posible capturar todas las fechas seleccionadas y almacenarlas en una colección de
fechas. En la Figura 48, observamos cómo, en modo de depuración, inspeccionamos el
resultado de la ejecución del código mostrando la lista de fechas seleccionadas.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
CollectionDateTime fechas = this.MiCalendario.SelectedDates;
}
Figura 48. Al inspeccionar la variable fechas, ésta nos muestra
todas las fechas seleccionadas por el usuario en el control Calendar.
El control Calendar, al igual que los demás controles, posee eventos que nos avisarán
de los cambios realizados por el usuario. Los tres eventos principales listados en el
código anterior son DisplayDateChanged, DisplayDatesChanged y DisplayModeChanged.
Los dos primeros están relacionados con la selección de fechas por parte del usuario:
mientras que DisplayDateChanged se disparará cada vez que el usuario seleccione una
nueva fecha, DisplayDatesChanged se disparará cuando el usuario modifique el rango
de fechas seleccionadas. Por otro lado, DisplayModeChanged se disparará cuando el
modo de presentación del calendario (Month, Year, Decade) sea alterado.
4. XAML AL EXTREMO
146
04_Silverlight.qxp 9/30/09 1:31 PM Page 146
basics:Calendar
DisplayDateChanged=”Calendar_DisplayDateChanged”
DisplayModeChanged=”Calendar_DisplayModeChanged”
SelectedDatesChanged=”Calendar_SelectedDatesChanged”
DisplayMode=”Decade”/
Control DatePicker
El control DatePicker es una extensión del control Calendar que vimos antes. Este con-
trol extiende la funcionalidad del calendario agregando una caja de texto para que el
usuario pueda escribir en ella una fecha sin tener que navegar en el calendario para
poder seleccionarla. Además, este control suele ocupar menos espacio al desplegar el
calendario cuando el icono de calendario a la derecha de la caja de texto es seleccio-
nado, ocultándolo una vez que la fecha fue seleccionada. La declaración es:
basics:DatePicker
/basics:DatePicker
Como este control es la unión de funcionalidades de un control Calendar y un control
TextBox, las propiedades y eventos aplicados al control DatePicker son las mismas que
las aplicadas al control Calendar. Podemos especificar fechas bloqueadas, día de inicio
de la semana, fechas seleccionadas por defecto, así como reducir la cantidad de fechas
navegables por el usuario. De igual forma, los eventos relacionados con este control
pueden ser copiados de los eventos usados por el control Calendar. Este control agrega
un nuevo atributo específico: SelectedDateFormat, que permite configurar la forma en
la que se mostrará la fecha seleccionada en la caja de texto. Las opciones son:
• Long: fecha en formato largo. La caja de texto mostrará la fecha usando el nombre
del día y el nombre del mes seleccionado, generando una fecha larga.
• Short: fecha en formato corto. La caja de texto utilizará el formato corto nu-
mérico (dd/mm/yyyy) para mostrar la fecha seleccionada.
Controles y componentes
147
,
Los formatos en los que se pueden expresar las fechas varían de acuerdo al país del usuario.
Por lo tanto, deberemos tener sumo cuidado al momento de manipular estos valores en aplica-
ciones que puedan ser consumidas desde diferentes ubicaciones en el mundo. Más información
en http://msdn.microsoft.com/es-es/.
MANEJO DE FECHAS
04_Silverlight.qxp 9/30/09 1:31 PM Page 147
Figura 49. Podemos ver el control DatePicker de la izquierda
con formato de fecha larga y a la derecha con formato de fecha corta.
Control ProgressBar
El control ProgressBar (barra de progreso) representa, típicamente, una línea que pue-
de mostrar el progreso evolutivo de una cosa. Es común ver este tipo de controles en
aplicaciones donde se cargan elementos de manera dinámica, mostrando el progreso de
esta carga mediante una barra de progreso. La declaración XAML es:
ProgressBar
/ProgressBar
Este control requiere de la configuración de dos atributos para especificar el valor
mínimo y el valor máximo aceptados para desplegar la barra interna de progreso.
• Minimum: este atributo representa el valor numérico mínimo que puede tomar la
barra de progreso. Casi siempre, el valor es equivalente a 0 (cero).
• Maximum: el valor máximo permitido que obtendrá la barra de progreso. Podemos
colocar un valor tan elevado como fracciones internas queramos tener. Esto quiere
decir que, si acumulamos valores para la barra de progreso avance de 10 en 10, y
nuestro máximo es de 100, sólo veremos 10 intervalos en la barra de progresos. Si
usamos un valor mayor o valores menores acumulativos, la barra de progresos se des-
plazará con más suavidad por tener un rango mayor de intervalos.
• Value: este atributo contiene el valor de la barra de progreso. Si asignamos un
valor inicial diferente del valor mínimo establecido, la barra de progresos se mos-
trará con información de progreso inicializada.
4. XAML AL EXTREMO
148
04_Silverlight.qxp 9/30/09 1:31 PM Page 148
Controles y componentes
149
Podemos asignar los valores de la siguiente forma:
ProgressBar Minimum=”0” Maximum=”100” Value=”50” x:Name=”MiProgressBar”
/ProgressBar
Figura 50. ProgressBar con progreso configurado.
La propiedad Value es la que deberemos usar en nuestro código para poder asig-
nar, en tiempo de ejecución, valores al control ProgressBar para que éste mues-
tre el estado y el progreso de la acción realizada. Para entender este concepto,
podemos simular un proceso de carga mediante la utilización de un cronómetro
o Timer, y hacer que, por cada intervalo ejecutado por este cronómetro, el con-
trol ProgressBar avance su barra de progreso.
Storyboard _temporizador = new Storyboard();
public Page()
{
InitializeComponent();
_temporizador.Duration = TimeSpan.FromMilliseconds(10);
_temporizador.Completed += new EventHandler(_temporizador_Completed);
}
private void _temporizador_Completed(object sender, EventArgs e)
{
if (this.MiProgressBar.Value  this.MiProgressBar.Maximum)
{
04_Silverlight.qxp 9/30/09 1:31 PM Page 149
this.MiProgressBar.Value += 1;
_temporizador.Begin();
}
}
private void IniciarProgressBar()
{
this.MiProgressBar.Value = 0;
_temporizador.Begin();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
IniciarProgressBar();
}
Por cada intervalo de temporizador, el valor del control ProgressBar es incre-
mentado en 1; esta acción se repite hasta que el valor actual de la barra de pro-
greso sea igual al valor máximo disponible en el control ProgressBar configurado
por medio de la propiedad Maximum.
Otro atributo útil con el que cuenta el control ProgressBar es IsIndeterminate,
que debemos utilizar cuando no sabemos con exactitud cuáles serán los valores
del progreso por mostrar. Al configurar el atributo con el valor True (verdadero),
el control mostrará un sinfín en la barra de progreso, que da a entender que se
desconoce el estado actual de progreso.
Figura 51. A la derecha, el control
ProgressBar con el atributo IsIndeterminate aplicado.
4. XAML AL EXTREMO
150
04_Silverlight.qxp 9/30/09 1:31 PM Page 150
También es posible utilizar nuestro propio patrón visual para mostrar como barra
de progreso. Como vemos en la Figura 52 que aparece debajo, utilizamos una ima-
gen como elemento de progreso y no un elemento de color plano. Si agregamos
un objeto del tipo ImageBrush dentro del tag ProgressBar.Foreground, cam-
biamos el color sólido de la barra de progreso por la imagen seleccionada.
ProgressBar Grid.Row=”1” Grid.Column=”0”
Minimum=”0” Maximum=”100” Value=”60”
Margin=”8,42,8,76” d:LayoutOverrides=”VerticalAlignment”
ProgressBar.Foreground
ImageBrush ImageSource=”http://www.redusers.com/wp-
content/themes/redusers/images/logo.jpg”/
/ProgressBar.Foreground
/ProgressBar
Figura 52. En este ejemplo, el control ProgressBar
usa una imagen como patrón para la barra de progreso.
Controles y componentes
151
RRR
Si bien hablamos de modos de ejecución y compilación, también existe el modo de depuración.
A este modo accedemos, por lo general, al presionar la tecla F5 en nuestra aplicación. Este
modo nos permitirá movernos línea a línea por nuestro código para poder depurarlo.
MODO DE DEPURACIÓN
04_Silverlight.qxp 9/30/09 1:31 PM Page 151
Control Slider
Slider es un control conocido por los desarrolladores de aplicaciones de escritorio. Pue-
de ser considerado una especie de potenciómetro, y al desplazar el medidor, el control
informará el valor aplicado por el usuario. Podemos declararlo de la siguiente forma:
Slider
/Slider
Algunos atributos del control Slider son similares al del control ProgressBar, pero
agrega otros específicos, que vemos a continuación:
• Minimum: al igual que con el control ProgressBar, este atributo representa el mí-
nimo valor posible que obtendrá el control Slider.
• Maximum: equivale al valor mayor posible que podrá obtener el control.
• SmallChange: cuando el usuario desplaza la barra del control Slider, este valor
representará el intervalo mínimo de esta acción. Así, si tenemos un valor equi-
valente a 1, el control se desplazará en intervalos pequeños. Con valores mayores,
los saltos serán equivalentes a este valor.
• LargeChange: en el caso de que el usuario no utilice el botón para modificar el valor
del control, sino que, por el contrario, presione sobre la barra del control Slider, es-
ta acción hará que el acumulador salte según el valor especificado en esta propiedad.
• Orientation: el control Slider puede visualizarse de dos formas, de manera horizon-
tal o vertical. Esta orientación se define mediante los valores Horizontal y Vertical.
Slider Minimum=”0” Maximum=”100”
LargeChange=”10” SmallChange=”1”
Orientation=”Vertical”
/Slider
Suscribiéndonos al evento ValueChanged, será posible disparar código cada vez
que el usuario modifique los valores del control. Tomaremos el valor actual del
control Slider mediante la propiedad Value.
Slider x:Name=”MiSlider” ValueChanged=”Slider_ValueChanged” Minimum=”0”
Maximum=”100”
LargeChange=”10” SmallChange=”1”
Orientation=”Vertical”
/Slider
4. XAML AL EXTREMO
152
04_Silverlight.qxp 9/30/09 1:31 PM Page 152
Figura 53. En este ejemplo, el control Slider se presenta de manera vertical.
En nuestro código C#, tomaremos este valor para mostrarlo en la aplicación. Como
resultado, cada vez que el usuario desplace la barra del control Slider, el control
TextBlock tomará este valor y lo mostrará.
private void Slider_ValueChanged(object sender,
RoutedPropertyChangedEventArgsdouble e)
{
this.textoSlider.Text = “Valor del Slider: “ +
this.MiSlider.Value.ToString();
}
Controles y componentes
153
… RESUMEN
En este capítulo hemos visto los controles nativos de Silverlight y cómo implementarlos por
medio de código XAML y desde C#. Si bien hemos podido interactuar con las principales
propiedades de estos controles, aún queda mucho por delante ya que es posible mezclarlos y
combinarlos de diferentes formas para obtener mejores interfaces visuales. Este capítulo es
una guía de referencia sobre los controles Silverlight, y, en los capítulos siguientes, utiliza-
remos lo que hemos visto aquí.
04_Silverlight.qxp 9/30/09 1:31 PM Page 153
154

PREGUNTAS TEÓRICAS
1 ¿XAML puede ser interpretado por siste-
mas no Microsoft?
2 ¿Cuál es el problema principal entre las in-
terfaces para distintas plataformas?
3 ¿Cómo ayuda el código XAML en la posibi-
lidad de transportar las interfaces entre
distintas plataformas?
4 ¿Cuántas maneras de cerrar elementos
XAML existen?
5 ¿En qué categorías podemos agrupar los
controles XAML?
6 ¿Es posible tener más de un control conte-
nedor como raíz del documento XAML?
7 ¿Es posible que el usuario desplace las co-
lumnas y filas de un control Grid sin nece-
sidad de generar código?
8 ¿Se pueden crear nuevos controles me-
diante la conjunción de dos o más contro-
les XAML?
9 ¿Qué contiene un archivo con extensión XAP?
10¿Qué atributo en los controles contenedo-
res de texto deberemos usar para obtener
el valor introducido por el usuario?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Cree dos grupos de controles RadioButton.
Intente que cada grupo trabaje de forma
independiente haciendo que la elección de
un control en un grupo no afecte el ele-
mento seleccionado en el segundo grupo.
2 Los controles pueden ser creados desde
código XAML. Intente crear un conjunto de
controles, pero desde código C#.
3 Habiendo agregado diferentes elementos
dentro de un control contenedor, recorra
cada uno de los elementos contenidos y
modifique sus valores desde código C#.
4 Ingrese en el sitio web de UXity (www.
uxity.com) para obtener ejemplos y mate-
rial sobre Silverlight en castellano.
5 Transforme un control HyperlinkButton pa-
ra que éste sea una imagen y no un texto.
04_Silverlight.qxp 9/30/09 1:31 PM Page 154
Luz, cámara,
acción
Mover objetos 156
Transformaciones 158
Transformación de traslación 159
Transformación de rotación 161
Transformación escalar 165
Transformación de distorsión 167
Aplicar todas
las transformaciones 168
Animaciones 170
DoubleAnimation 171
ColorAnimation 173
Animaciones
y transformaciones 175
Estilos y plantillas 178
Estilos 178
Plantillas 182
Resumen 185
Actividades 186
Capítulo 5
La forma de presentar la información
no se reduce a colocar controles
en posiciones específicas, sino
a la habilidad de poder presentar
esta información de la mejor manera
y con el mayor dinamismo posible.
En este capítulo veremos cómo
agregar el factor dinámico a nuestras
aplicaciones, mediante el uso
de animaciones y comportamientos.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
05_Silverlight.qxp 9/30/09 1:32 PM Page 155
MOVER OBJETOS
En los capítulos anteriores, hemos usado Silverlight para desplegar información des-
de fuentes de datos, permitiendo al usuario interactuar con éstos. Podríamos decir
que, de alguna forma, hemos creado interfaces de la manera tradicional, colocando
controles en un espacio bidimensional, tratando de llenar el espacio especificado pa-
ra la interfaz de la mejor forma posible. Y cuando hacemos referencia a la mejor for-
ma posible, en realidad queremos decir que, muchas veces, las aplicaciones tratan de
ocupar por completo cualquier espacio disponible de la superficie de la interfaz, co-
locando botones o cualquier otro tipo de controles allí donde exista un espacio en
blanco. Esto se debe al hecho de que, con el avance de la tecnología y de la infor-
mación en general, cada vez más las aplicaciones de software necesitan mostrar ma-
yor cantidad de datos en pantalla, ya que el usuario requiere ver más información al
mismo tiempo sin tener que navegar entre diferentes ventanas o pulsar varios boto-
nes para conseguir lo que le interesa. Por otro lado, tener que moverse de un lado al
otro, y abrir y cerrar ventanas, muchas veces trae como consecuencia que datos im-
portantes queden ocultos por las nuevas ventanas, y se llegue al punto en el que el
usuario olvide por completo el porqué de la búsqueda inicial. Este tipo de desarrollo
se propagó, en especial, por la falta de soporte de los sistemas operativos y por la com-
plejidad de desarrollo de los variados lenguajes de programación usados para crear las
diferentes aplicaciones. En muchos casos, las interfaces de las aplicaciones, por estas
restricciones, llegan a presentarse como la que podemos ver en la siguiente figura.
Figura 1. Una interfaz sobrecargada es poco práctica para el usuario.
Existen diferentes formas de mejorar la experiencia del usuario en nuestras apli-
caciones, así como también es posible optimizar el espacio de nuestra aplicación
5. LUZ, CÁMARA, ACCIÓN
156
05_Silverlight.qxp 9/30/09 1:32 PM Page 156
para mostrar, de forma más natural para el usuario, la información requerida. Si
bien no es el objetivo de este libro hablar de estas técnicas, resulta importante man-
tener este pensamiento en el momento de realizar el diseño de aplicaciones. De cual-
quier manera, una de estas técnicas, cada vez más usada, es la de desplazar o mover
objetos dentro del área de la interfaz de la aplicación. De esta forma, los elementos
principales se mantienen todo el tiempo visibles, de manera constante, y dan paso
a otros elementos creados a partir de la selección o interacción del usuario con los
elementos más importantes. Por esto, el movimiento de objetos no resulta ajeno a
Silverlight, que permite modificar los estados, formas, tamaños y posición de los di-
ferentes controles mientras ejecutamos nuestra aplicación. Durante este capítulo,
hablaremos de las características provistas por Silverlight para poder mejorar las in-
terfaces de las aplicaciones por medio del uso de movimiento y modificación del
comportamiento visual de los controles y de los componentes.
Figura 2. Una vista de Microsoft Surface,
que permite arrastrar y mover elementos al tocarlos con la mano.
Mover objetos
157
RRR
Una interfaz de usuario demasiado cargada ocasionará rechazo por parte de éste. Es necesario,
siempre que podamos, dejar las interfaces lo más simples y claras posibles, incluso moviendo
los elementos en la pantalla durante la ejecución y abriendo la menor cantidad posible de ven-
tanas o elementos que obstruyan la visión de datos importantes.
INTERFAZ DE USUARIO
05_Silverlight.qxp 9/30/09 1:32 PM Page 157
Transformaciones
Las transformaciones son uno de los modificadores de objetos disponibles en Sil-
verlight. Con ellas, es posible cambiar la apariencia y el comportamiento de los con-
troles y componentes de la interfaz. Es posible rotarlos, escalarlos, distorsionarlos,
modificar su posición relativa a un punto, así como invertir su posición vertical u ho-
rizontal. Podemos ver, a continuación, la lista de transformaciones disponibles:
• Transformación de traslación: esta transformación modifica la posición del objeto
dentro del eje de coordenadas X e Y. Es útil para desplazar o ajustar el objeto en una
coordenada específica en forma independiente de la posición dentro del contenedor.
• Transformación de rotación: la transformación de rotación sirve para girar el
objeto sobre la base de una cantidad de grados definida. Esta transformación otor-
ga la libertad suficiente para amoldar controles típicamente horizontales y verti-
cales, como botones y grillas de datos, entre otros, en posiciones no tradicionales.
• Transformación escalar: una transformación escalar hace referencia a la posibi-
lidad de modificar el tamaño o la escala del objeto Silverlight. Si aplicamos esta
transformación, podremos agrandar o achicar el tamaño del objeto, incluido su
contenido. Debido a que los controles y los componentes en XAML se forman
según la conjunción de otros elementos, al aplicar esta transformación, Silverlight
aplicará la misma a todos los elementos internos del objeto modificado, por lo que
no tendremos que preocuparnos por las proporciones de esos elementos internos,
ya que estos se ajustarán en forma proporcional a su contenedor.
• Transformación de distorsión: la transformación de distorsión o la acción de
sesgado permite torcer los objetos para el eje X e Y. Este mecanismo resulta
ideal en aquellos casos en los cuales necesitemos simular elementos de tres di-
mensiones en un ambiente bidimensional o si queremos generar algún tipo de
perspectiva en los objetos.
Debido a que es posible aplicar más de una transformación al mismo tiempo sobre
un objeto, éstas pueden ser agrupadas dentro de un tag XAML común. El tag
TransformGroup representa esta agrupación y deberemos usarlo como agrupa-
dor de los otros tags representativos para cada transformación.
5. LUZ, CÁMARA, ACCIÓN
158
RRR
Al aplicar una transformación a cualquier objeto, éste se redibujará en forma instantánea. Esto
es por demás útil para generar animaciones en tiempo de ejecución en nuestra aplicación, ya que
no necesitaremos de cálculos o de imágenes pregeneradas para conseguir el efecto deseado.
TRANSFORMACIONES
05_Silverlight.qxp 9/30/09 1:32 PM Page 158
Figura 3. Un control DataGrid con diferentes transformaciones aplicadas.
Las transformaciones, así como otros efectos en Silverlight, son generados en
tiempo de ejecución y de manera dinámica. Esto resulta muy beneficioso en com-
paración con otras tecnologías, ya que el tamaño del archivo de Silverlight creado
resulta mucho más pequeño. Esto se debe a que no es necesario que se genere
por cada efecto un nuevo elemento con el resultado del efecto. Si pensamos en
una transformación sobre una imagen de tamaño considerable, por cada transforma-
ción aplicada a ésta, se podría generar una nueva imagen con el nuevo resultado. Si
se agregara cada una de ellas al archivo final, se acrecentaría su tamaño en una
proporción equivalente al tamaño de la imagen por la cantidad de imágenes creadas.
Al calcular los efectos en tiempo de ejecución, esto se evita, y así se mejora enor-
memente la optimización en la utilización de recursos.
Transformación de traslación
La transformación de traslación es usada para desplazar o colocar un objeto en una
posición en X y en Y dentro del lienzo de una aplicación. En la Figura 4, el rectángulo
se encuentra por encima de la línea que divide las dos columnas de la grilla.
Mover objetos
159
RRR
Los controles de agrupación, como vimos en capítulos anteriores, pueden contener otros con-
troles y manejarlos como un conjunto agrupado. Si necesitamos mover más de un control al
mismo tiempo, es posible aplicar una transformación de traslación al contenedor de estos
controles en lugar de hacerlo uno por uno.
TRASLACIÓN EN AGRUPADORES
05_Silverlight.qxp 9/30/09 1:32 PM Page 159
Figura 4. El rectángulo se muestra desplazado en X y en Y.
En el código de la Figura 4, podemos notar algunas cuestiones interesantes obte-
nidas al haber aplicado la transformación.
Grid x:Name=”LayoutRoot” Background=”White” ShowGridLines=”True”
Grid.RowDefinitions
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
ColumnDefinition/
/Grid.ColumnDefinitions
Rectangle Height=”30” Grid.Column=”0” Grid.Row=”0”
VerticalAlignment=”Top” Fill=”#FFAF2727”
Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5”
Rectangle.RenderTransform
TransformGroup
TranslateTransform X=”150” Y=”150”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
/Grid
Si bien hemos definido dos columnas y una fila en la grilla, y el rectángulo está po-
sicionado en la primera columna y la primera fila de acuerdo con los atributos
5. LUZ, CÁMARA, ACCIÓN
160
05_Silverlight.qxp 9/30/09 1:32 PM Page 160
Grid.Column y Grid.Row, debido a la transformación aplicada, éste se encuentra des-
plazado 150 pixeles en el eje X y 150 pixeles en el eje Y.
Transformación de rotación
Con esta transformación, podremos rotar cualquier objeto. Aplicando la misma
transformación al rectángulo anterior, obtenemos el resultado que observamos en
la Figura 5. Para conseguir esta transformación debemos aplicar el siguiente código.
Grid x:Name=”LayoutRoot” Background=”White”
Rectangle Margin=”87,144,155,127” Fill=”#FF4366DE” Stroke=”#FF000000”
RenderTransformOrigin=”0.5,0.5”
Rectangle.RenderTransform
TransformGroup
RotateTransform Angle=”45”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
/Grid
Figura 5. Un rectángulo rotado 45 grados a favor del reloj.
RotateTransform posee dos atributos adicionales que resultan útiles para espe-
cificar el punto de rotación. En el ejemplo anterior, el punto de rotación había
sido especificado mediante el atributo RenderTransformOrigin, separando con una
coma el punto de rotación en X y en Y. En este ejemplo, el punto de rotación se
encuentra posicionado en el centro del objeto especificando 0.5 (50%) para X y
Mover objetos
161
05_Silverlight.qxp 9/30/09 1:32 PM Page 161
0.5 (50%) para Y. Como resultado, teniendo una copia del mismo rectángulo,
pero con una rotación de 90 grados, éste gira sobre el punto central del elemento.
Si bien podemos utilizar RenderTransformOrigin, también es válido utilizar los
atributos CenterX y CenterY dentro del tag RotateTransform para realizar el mis-
mo trabajo que el del atributo anterior. En la Figura 6, vemos los dos casos. En
ellos, a un grupo de elementos, no se le especifica un punto de rotación, lo que
causa que este punto sea el extremo superior izquierdo.
Figura 6. Dos grupos de rectángulos con su centro de rotación modificado.
Podemos ver en el siguiente código las diferencias aplicadas en cada caso.
Rectangle Margin=”18,146,0,125” Fill=”#FF4366DE” Stroke=”#FF000000”
RenderTransformOrigin=”0.5,0.5” HorizontalAlignment=”Left” Width=”158”
Rectangle.RenderTransform
TransformGroup
RotateTransform Angle=”45”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
Rectangle Margin=”18,146,0,125” Fill=”#FF4366DE” Stroke=”#FF000000”
HorizontalAlignment=”Left” Width=”158”
Rectangle.RenderTransform
TransformGroup
RotateTransform Angle=”90” CenterX=”79” CenterY=”15”/
/TransformGroup
5. LUZ, CÁMARA, ACCIÓN
162
05_Silverlight.qxp 9/30/09 1:32 PM Page 162
/Rectangle.RenderTransform
/Rectangle
Rectangle Margin=”0,86,26,0” Fill=”#FF4366DE” Stroke=”#FF000000”
Width=”158” HorizontalAlignment=”Right” VerticalAlignment=”Top”
Height=”29”
Rectangle.RenderTransform
TransformGroup
RotateTransform/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
Rectangle Margin=”0,86,26,0” Fill=”#FF4366DE” Stroke=”#FF000000”
Width=”158” HorizontalAlignment=”Right” Height=”29”
VerticalAlignment=”Top”
Rectangle.RenderTransform
TransformGroup
RotateTransform Angle=”30”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
...
Un punto que debemos tener en cuenta sobre cuál de los dos atributos necesita-
mos usar radica en la forma de calcular la posición del punto de rotación. Por su
parte, RenderTransformOrigin utiliza un valor porcentual, siendo 1 equivalente a
100%. Si el valor de RenderTransformOrigin es equivalente a “1,1”, éste será igual
a la esquina inferior derecha, mientras que “0,0” representará la esquina superior
izquierda. Este método para especificar el punto de rotación puede resultar, en
algunos casos, más fácil de calcular, en especial para deducir el centro de rota-
ción, ya que éste es representado por el valor “0.5,0.5”. Sin embargo, podría ser
complejo de calcular para puntos intermedios.
Por otro lado, para el caso de CenterX y CenterY, se utilizan valores numéricos
equivalentes al tamaño del objeto por rotar. Así, si el objeto ocupa 100 pixeles
de ancho y 50 pixeles de alto, el valor para CenterX deberá ser de 50, mientras el
valor para CenterY deberá ser de 25. Como ya dijimos, los controles y compo-
nentes también pueden ser afectados por estas transformaciones. Ellos seguirán
prestando la misma funcionalidad, pero, en lo visual, se desplegarán basados en
su transformación. En la Figura 7, vemos cómo una serie de controles aplican la
transformación de rotación sin perder funcionalidad.
Mover objetos
163
05_Silverlight.qxp 9/30/09 1:32 PM Page 163
Figura 7. Controles para entrada de datos con transformación de rotación.
En el siguiente código, vemos ambos controles.
Button HorizontalAlignment=”Left” Margin=”0,45,0,0” VerticalAlignment=”Top”
Content=”Aceptar” d:LayoutOverrides=”Width”
RenderTransformOrigin=”0.5,0.5”
Button.RenderTransform
TransformGroup
RotateTransform Angle=”-90”/
/TransformGroup
/Button.RenderTransform
/Button
TextBox HorizontalAlignment=”Left” Margin=”-55,0,0,123”
VerticalAlignment=”Bottom” Width=”158” RenderTransformOrigin=”0.5,0.5”
Text=”” TextWrapping=”Wrap” d:LayoutOverrides=”Height”
TextBox.RenderTransform
TransformGroup
RotateTransform Angle=”-90”/
/TransformGroup
/TextBox.RenderTransform
/TextBox
Si bien los valores para el punto de rotación que hemos usado hasta el momento se
aplican a la parte interna del objeto rotado, es posible utilizar valores que sobrepa-
5. LUZ, CÁMARA, ACCIÓN
164
05_Silverlight.qxp 9/30/09 1:32 PM Page 164
sen los límites del objeto por rotar. De esta manera, conseguiremos que el eje de ro-
tación quede fuera del objeto. Esto hará que el punto de rotación marque la posi-
bilidad de rotación por sobre una circunferencia y permitirá que el elemento gire
alrededor de este punto como si se tratase de una órbita en un punto específico.
Transformación escalar
La transformación escalar es útil para modificar el tamaño de los objetos, tanto
en largo como en alto o en una escala para X como para Y, si trasladamos las di-
mensiones a un eje XY. En la figura que vemos a continuación, podemos apre-
ciar dos rectángulos con sus respectivas modificaciones.
Figura 8. Dos rectángulos modificados por la transformación escalar.
Los atributos utilizados para modificar la escala de los objetos son ScaleX y ScaleY,
ambos usados dentro del tag ScaleTransform, que hace referencia a este tipo de trans-
formación. Podemos ver el código utilizado para generar la Figura 8 a continuación.
Rectangle Margin=”125,57,149,0” Fill=”#FF82D442” Stroke=”#FF000000”
RenderTransformOrigin=”-0.008,0.967” Height=”30”
VerticalAlignment=”Top”
Rectangle.RenderTransform
TransformGroup
ScaleTransform ScaleX=”1.3” ScaleY=”1.3”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
Mover objetos
165
05_Silverlight.qxp 9/30/09 1:32 PM Page 165
Rectangle Margin=”125,57,149,0” Fill=”#FF9FCE7A” Stroke=”#FF000000”
Height=”30” VerticalAlignment=”Top”/
Rectangle Margin=”125,0,149,106” Fill=”#FF406225” Stroke=”#FF000000”
Height=”30” VerticalAlignment=”Bottom” RenderTransformOrigin=”0.5,0.5”
Rectangle.RenderTransform
TransformGroup
ScaleTransform ScaleX=”1.3” ScaleY=”1.3”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
Rectangle Margin=”125,0,149,106” Fill=”#FF293B1A” Stroke=”#FF000000”
Height=”30” VerticalAlignment=”Bottom”/
ScaleX y ScaleY utilizan un valor numérico que representa el porcentaje de creci-
miento que recibirá el objeto. En el ejemplo, utilizamos el valor 1.3, que represen-
ta el 100% del tamaño original más un 30% adicional, por lo que el objeto habrá
crecido 30%, tanto en X como en Y. Al igual que la transformación de rotación,
la transformación escalar también hace uso de los atributos CenterX y CenterY, así
como de RenderTransformOrigin, aplicando las mismas reglas antes mencionadas.
En la Figura 9, podemos ver dónde está posicionado el eje de crecimiento para el
rectángulo superior, el cual es cercano a la esquina inferior izquierda del objeto.
El rectángulo inferior utiliza su centro como punto de crecimiento. Debido a es-
to, vemos que este rectángulo crece hasta cubrir el rectángulo original, y lo hace
desde su centro hacia las cuatro direcciones del eje XY.
Figura 9. El rectángulo superior modifica su eje de crecimiento.
5. LUZ, CÁMARA, ACCIÓN
166
05_Silverlight.qxp 9/30/09 1:32 PM Page 166
Transformación de distorsión
Esta última transformación modifica la apariencia del objeto aplicando ángulos de
torsión. Pensemos en un objeto de forma cuadrada o rectangular. Cada esquina de
este objeto es representada por un ángulo de 90 grados. Esta transformación tiene
el objetivo de modificar estos ángulos rectos sobre la base de un valor numérico ex-
presado, también, en grados. En la siguiente figura, vemos cómo es distorsionada la
apariencia de un objeto cuadrado.
Figura 10. El objeto es distorsionado para generar una vista en perspectiva.
En el código que aparece a continuación, podemos ver que los atributos AngleX
y AngleY son configurados con los valores de -10 grados cada uno. Estos dos atri-
butos, junto con RenderTransformOrigin, son los que le otorgan el aspecto final
al objeto una vez distorsionado.
Si modificamos el valor RenderTransformOrigin para que se encuentre fuera del
centro del objeto, conseguiremos distorsiones no simétricas, que pueden ser úti-
les, basadas en la perspectiva que queramos lograr.
Rectangle Margin=”134,102,186,118” Fill=”#FF43A6C3” Stroke=”#FF000000”
RenderTransformOrigin=”0.5,0.5”
Rectangle.RenderTransform
TransformGroup
SkewTransform AngleX=”-10” AngleY=”-10”/
/TransformGroup
/Rectangle.RenderTransform
/Rectangle
Mover objetos
167
05_Silverlight.qxp 9/30/09 1:32 PM Page 167
Aplicar todas las transformaciones
Como mencionamos, es posible aplicar más de una transformación a nuestros ob-
jetos, incluso, se pueden aplicar estas transformaciones a los controles para entrada
de datos, así como para aquellos que despliegan la información. Para poner en prác-
tica esto, extenderemos un poco el ejemplo creado en el capítulo 3, modificando la
apariencia del control DataGrid, además de agregar algunos otros elementos llama-
tivos a la interfaz creada para ese ejemplo.
Figura 11. Resultado final después de haber
aplicado transformaciones a los controles Silverlight.
El primer paso, consiste en aplicar transformaciones a nuestro DataGrid, que estará
ubicado en una de las dos columnas de la grilla contenedora. Además, el control
DataGrid fue colocado dentro de un control Border para simular las puntas redondea-
das, aplicándole un color degradado. Estos controles, finalmente, se encuentran den-
tro de un control StackPanel. Sobre este StackPanel, aplicaremos las transformaciones.
Grid x:Name=”LayoutRoot”
Grid.RowDefinitions
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition Width=”0.512*”/
ColumnDefinition Width=”0.488*”/
/Grid.ColumnDefinitions
Grid.Background
5. LUZ, CÁMARA, ACCIÓN
168
05_Silverlight.qxp 9/30/09 1:32 PM Page 168
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF2A77FF”/
GradientStop Color=”#FFFFFFFF” Offset=”1”/
/LinearGradientBrush
/Grid.Background
StackPanel HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”
Margin=”0,0,8,0” RenderTransformOrigin=”0.5,0”
StackPanel.RenderTransform
TransformGroup
ScaleTransform ScaleY=”1”/
SkewTransform AngleY=”-28”/
RotateTransform/
TranslateTransform Y=”25”/
/TransformGroup
/StackPanel.RenderTransform
TextBlock FontFamily=”Arial” FontSize=”20” FontStyle=”Normal”
FontWeight=”Bold” Text=”Registros disponibles” TextWrapping=”Wrap”/
Border BorderThickness=”1,1,1,1” CornerRadius=”10,10,10,10”
BorderBrush=”#FF000000” Height=”450”
Border.Background
LinearGradientBrush EndPoint=”0.5,1”
StartPoint=”0.5,0”
GradientStop Color=”#FF9BD3E8”/
GradientStop Color=”#FF2D88A9”
Offset=”1”/
/LinearGradientBrush
/Border.Background
data:DataGrid BorderThickness=”0,0,0,0”
HorizontalContentAlignment=”Center” VerticalContentAlignment=”Center”
x:Name=”MiGrilla” Height=”400” HorizontalAlignment=”Center”
VerticalAlignment=”Center” Width=”300”/
/Border
/StackPanel
Para mostrar la cantidad de registros seleccionados en cada búsqueda, usamos un
control TextBlock con una transformación de rotación.
TextBlock HorizontalAlignment=”Right” VerticalAlignment=”Bottom”
Text=”Registros” TextWrapping=”Wrap” Grid.Column=”1”
Mover objetos
169
05_Silverlight.qxp 9/30/09 1:32 PM Page 169
d:LayoutOverrides=”HorizontalAlignment, Height” Margin=”0,0,-
172.962,76.866” RenderTransformOrigin=”0,1” Opacity=”0.5” FontSize=”48”
FontFamily=”Lucida Sans Unicode” FontWeight=”Bold” FontStyle=”Normal”
x:Name=”registros” Width=”318.554”
TextBlock.RenderTransform
TransformGroup
ScaleTransform/
SkewTransform/
RotateTransform Angle=”-90”/
TranslateTransform Y=”76.23” X=”150.674”/
/TransformGroup
/TextBlock.RenderTransform
/TextBlock
Luego, modificamos el código encargado de realizar las búsquedas sobre la base del tex-
to introducido por el usuario para desplegar la cantidad de registros encontrados.
private void Button_Click(object sender, RoutedEventArgs e)
{
var q = from c in productos
where c.Nombre.Contains(this.buscador.Text)
|| c.Descripcion.Contains(this.buscador.Text)
select c;
this.MiGrilla.ItemsSource = q;
this.registros.Text = “Registros “ + q.CountProducto().ToString();
}
De esta manera, probamos que las transformaciones pueden ser no sólo aplicadas a
formas básicas, sino a cualquier elemento creado por código XAML.
Animaciones
Como hemos notado con las transformaciones, éstas no generan nuevos ele-
mentos del objeto modificado, sino que actúan sobre él en tiempo de ejecución
de la aplicación Silverlight. Esto ahorra, por un lado, los recursos transmitidos
hacia el cliente que visualiza nuestra aplicación, y por otro, nos da la posibilidad
de modificar estas transformaciones en tiempo de ejecución, no atándonos a un
guión establecido con anterioridad. Basadas en este modelo, las animaciones en
5. LUZ, CÁMARA, ACCIÓN
170
05_Silverlight.qxp 9/30/09 1:32 PM Page 170
Silverlight se diferencian bastante de los modelos tradicionales de animación,
que, por lo general, se representan mediante la creación de cuadros reproducidos
en forma sucesiva. Este modelo, el del cuadro a cuadro, también resulta costoso en
recursos de cara al usuario, ya que por cada cuadro es necesario transmitir cada uno
de éstos como si se tratara de la reproducción de una película o de un dibujo ani-
mado. Pero además, renace el problema de elementos guionados, que nos llevan
a pensar en todas las posibles alternativas que los elementos de nuestra aplica-
ción podrían tener. Por el contrario, Silverlight utiliza para las animaciones el
mismo modelo que hemos visto en las transformaciones. Esto significa que po-
dremos animar los distintos elementos de nuestra aplicación en tiempo de eje-
cución, pudiendo alterar o generar nuevo contenido basado en las necesidades
del usuario. A pesar de esto, es posible que la cantidad de animaciones que podamos
generar con Silverlight parezcan limitadas, ya que el modelo reduce esta canti-
dad a tres tipos de animaciones, los cuales tendrán la capacidad de modificar las
propiedades y los atributos de los objetos por animar.
• DoubleAnimation: este modelo de animación está orientado a modificar los valo-
res numéricos de las propiedades y atributos del objeto.
• ColorAnimation: este tipo de animación es utilizado para modificar valores que no
pueden ser representados por números reales. Los colores, por ejemplo, suelen re-
presentarse en hexadecimal.
• PointAnimation: esta animación tiene la capacidad de modificar valores en propieda-
des que trabajen con puntos. Este modelo de animación está fuertemente relaciona-
do con movimientos de objetos y con el desplazamiento en el eje de coordenadas XY.
DoubleAnimation
Como dijimos, este modelo de animación es útil cuando queremos modificar los
valores numéricos de las propiedades y atributos de cualquier objeto. Para declarar
una animación de este tipo, podemos usar el siguiente código:
DoubleAnimation From=”128” To=”200” Duration=”0:0:10”/
Los atributos From (desde) y To (hasta) determinarán los rangos entre los cuales el
atributo por modificar se irá alternando. En el caso anterior, el valor en cuestión
irá desde 128 a 200; estos valores se distribuirán de acuerdo con el tiempo especi-
ficado por el atributo Duration (duración). Este último atributo es representado por
los valores correspondientes a horas, minutos y segundos (hh:mm:ss). Para el ejem-
plo, la animación tendrá una duración de 10 segundos. En la Figura 12, vemos
cómo, al aplicar esta animación sobre la propiedad Width de un rectángulo, éste
modifica su tamaño según dicha animación.
Mover objetos
171
05_Silverlight.qxp 9/30/09 1:32 PM Page 171
Figura 12. El rectángulo en el navegador de la izquierda, antes
de que ocurriese la animación; y el de la derecha, una vez ocurrida.
Para lograr esto, lo primero que deberemos hacer es crear nuestro rectángulo.
Grid x:Name=”LayoutRoot” Background=”White”
Rectangle MouseEnter=”Rectangulo_MouseEnter” x:Name=”Rectangulo”
Height=”55” HorizontalAlignment=”Left”
Margin=”69,57,0,0” VerticalAlignment=”Top”
Width=”128” Fill=”#FF407280” Stroke=”#FF000000”
/Rectangle
/Grid
Una vez que tenemos el rectángulo en posición, deberemos crear la animación.
UserControl.Resources
Storyboard x:Name=”Animacion1”
DoubleAnimation From=”128” To=”200” Duration=”0:0:01”
Storyboard.TargetProperty=”Width”
Storyboard.TargetName=”Rectangulo”/DoubleAnimation
/Storyboard
/UserControl.Resources
Esta animación es considerada un recurso genérico de todo el control XAML,
por este motivo, deberemos colocarla dentro del tag UserControl.Resources.
5. LUZ, CÁMARA, ACCIÓN
172
05_Silverlight.qxp 9/30/09 1:32 PM Page 172
El siguiente tag es el Storyboard. Este tag agrupará en un conjunto todas las ani-
maciones que se van a aplicar a un mismo objeto o, si lo preferimos, animaciones
para diferentes objetos que podremos ejecutar al mismo tiempo como un conjun-
to. Es importante la presencia de un nombre para el tag Storyboard por medio del
atributo x:Name, ya que de esta forma podremos iniciar la ejecución del conjunto
de animaciones invocando su nombre. Los atributos del tag DoubleAnimation,
Storyboard. TargetProperty y Storyboard.TargetName hacen referencia a la propiedad
que esa animación modificará y al nombre del objeto que contiene la propiedad, res-
pectivamente. Para este caso, Storyboard.TargetProperty hace referencia a la propiedad
Width del objeto definido por Storyboard.TargetName, que en este caso es Rectangulo.
Para activar la animación, es necesario especificar el momento en el cual ésta se ini-
ciará. Esto lo logramos desde nuestro código C#, de la siguiente manera, donde
animación es el nombre previamente configurado en el tag Storyboard:
this.Animacion1.Begin();
ColorAnimation
ColorAnimation es necesaria para animaciones que modifiquen el color de los obje-
tos. Posee iguales atributos que los presentados en la animación del tipo DoubleAnimation
y, para usarla, deberemos declararla como sigue:
ColorAnimation/ColorAnimation
Figura 13. A la derecha, el rectángulo presenta un cambio
de color, el mismo que fue aplicado en forma paulatina con la animación.
Mover objetos
173
05_Silverlight.qxp 9/30/09 1:32 PM Page 173
La declaración completa de esta animación podemos verla a en el siguiente código,
que pasa del color original del rectángulo hasta el color negro definido por el atri-
buto To. En este caso, modificamos la propiedad Fill, y su atributo Color.Storyboard.
TargetProperty hace referencia a este conjunto de propiedades y atributos.
ColorAnimation From=”#FF407280” To=”#FF000000” Duration=”0:0:01”
Storyboard.TargetProperty=”(Fill).(Color)”
Storyboard.TargetName=”Rectangulo”/ColorAnimation
PointAnimation
PointAnimation es el último de los modelos de animación propuestos por Silverlight.
Puede ser usado para modificar puntos de coordenadas XY. Para declarar esta ani-
mación, debemos hacerlo de la siguiente manera:
PointAnimation/PointAnimation
Para graficar este modelo de animación, crearemos un círculo que desplazaremos
sobre la base de su centro de dibujo. Podemos declarar este elemento como sigue:
Path Fill=”#FF407280” MouseEnter=”Path_MouseEnter”
Path.Data
EllipseGeometry x:Name=”GeometriaCircular”
Center=”200,200” RadiusX=”40” RadiusY=”40” /
/Path.Data
/Path
Figura 14. Este círculo se desplazará sobre la base de su centro de dibujo.
5. LUZ, CÁMARA, ACCIÓN
174
05_Silverlight.qxp 9/30/09 1:32 PM Page 174
La animación por puntos la declararemos dentro de su propio tag Storyboard, el
cual modificará el atributo Center del círculo creado.
Storyboard x:Name=”Animacion2”
PointAnimation From=”0,200” To=”300,200” Duration=”0:0:2”
Storyboard.TargetName=”GeometriaCircular”
Storyboard.TargetProperty=”Center” /PointAnimation
/Storyboard
Debido a que se trata de un punto en el mapa de coordenadas, tanto el atributo
From como To presentan el patrón XY separados por una coma. Al aplicar esta ani-
mación, veremos que el círculo se desplazará de izquierda a derecha cubriendo 300
pixeles de distancia en 2 segundos. Como ya hemos podido notar, los atributos de
configuración para las animaciones son los mismos entre los modelos, y existen otros
elementos comunes para estas animaciones que pueden ser de utilidad.
• RepeatBehavior: este atributo dictamina la cantidad de veces que la animación se
repetirá una vez que llegue a su fin. Podemos configurar para que se repita una
cantidad de veces determinada usando un valor numérico, o la palabra Forever
(para siempre), para que la animación sea continua.
• AutoReverse: es posible optar entre True (verdadero) o False (falso). Si configuramos
esta propiedad en True, la animación retrocederá sobre sus pasos una vez finalizada.
• SpeedRatio: este atributo representa la velocidad en la animación. Por defecto, el
valor utilizado es 1, lo que quiere decir que la animación trabajará a velocidad nor-
mal. Si incrementamos este valor a 2, la animación será dos veces más rápida que
la velocidad normal. Este valor no es relación de cuadros por segundo, sino la ra-
pidez o lentitud con las que avanzará y concluirá la animación. Así, si tenemos
una animación con una duración de 5 segundos y configuramos el valor de este
atributo a 2, la animación debería concluir en 2 segundos y medio, pero, si el va-
lor es equivalente a 0.5, la animación tardaría el doble.
• BeginTime: representa un lapso de tiempo que la animación esperará antes de
iniciarse. Este lapso es representado de igual forma que el del atributo Duration,
mediante la nomenclatura hh:mm:ss.
Animaciones y transformaciones
Con un poco de imaginación, veremos que la combinación de animaciones con los
atributos de los controles nos puede dar suficiente libertad como para hacer casi todo
lo que necesitemos. Podríamos por ejemplo, conjugar animaciones con las transfor-
maciones vistas al principio de este capítulo para conseguir no sólo modificar tamaños,
colores o posiciones de los objetos, sino también poder cambiar de aspecto, rotarlo,
Mover objetos
175
05_Silverlight.qxp 9/30/09 1:32 PM Page 175
distorsionarlo o agrandarlo a gusto. Para graficar esto, utilizaremos un objeto al cual le
aplicaremos una animación para una transformación de rotación.
Figura 15. Animando una transformación de rotación.
El primer paso consiste en declarar el objeto con los valores de la transformación.
Es importante tener estos valores por defecto ya que, de no existir, no podrían ser
encontrados por el elemento que genera la animación.
Rectangle Height=”29” VerticalAlignment=”Top”
Margin=”149,83,116,0” Fill=”#FFBF3434”
MouseEnter=”Rectangle_MouseEnter”
Rectangle.RenderTransform
RotateTransform Angle=””
x:Name=”anguloRectangulo”/RotateTransform
/Rectangle.RenderTransform
/Rectangle
También podemos ver que el elemento RotateTransform tiene un atributo x:Name,
lo que hará que sea mucho más simple poder acceder a él desde la animación y no
tener que crear cadenas de texto largas para indicar cuál es el atributo sobre el que
actuará la animación. Por último, creamos la animación para esta transformación:
Storyboard x:Name=”Animacion”
DoubleAnimation From=”0” To=”90”
5. LUZ, CÁMARA, ACCIÓN
176
05_Silverlight.qxp 9/30/09 1:33 PM Page 176
Storyboard.TargetName=”anguloRectangulo”
Storyboard.TargetProperty=”Angle”/DoubleAnimation
/Storyboard
La animación se aplicará sobre el atributo Angle (ángulo), aplicándole grados que
pueden ir desde 0 a 90. Para dar inicio a esta animación, deberemos escribir el
código que vemos a continuación:
private void Rectangle_MouseEnter(object sender, MouseEventArgs e)
{
this.Animacion.Begin();
}
Figura 16. Podremos aplicar este tipo de transformaciones
a cualquier elemento. En este caso, animamos un control
DatePicker mediante una transformación de rotación.
Mover objetos
177
_`
Debido a que podemos definir líneas sinusoidales, las cuales cuentan con puntos XY de inicio y
puntos XY de finalización además de un radio de curva, es posible usar PointAnimation para ani-
mar esta curva en tiempo de ejecución para lograr efectos de ondas.
ANIMAR CURVAS
05_Silverlight.qxp 9/30/09 1:33 PM Page 177
Estilos y plantillas
En la mayoría de los casos, usamos los controles provistos por Silverlight tal como son,
sin modificar su apariencia visual predefinida. Esto puede ser útil en muchos casos, pe-
ro existirán muchas ocasiones en las que deberemos adaptar estos elementos a nuestros
diseños, y modificar las propiedades visuales de los componentes. Para lograr esto, so-
lemos cambiar la apariencia visual control por control, algo que consumirá tiempo y
será costoso, además de generar código XAML innecesario, agrandando el tamaño de
nuestra aplicación y haciéndola mucho más complicada de modificar y mantener. Ima-
ginemos que nuestra aplicación cuenta con veinte botones y que, después de haber mo-
dificado y terminado nuestro trabajo, nos encontramos con un nuevo requerimiento
que implica tener que volver a cambiar el aspecto de estos botones. Hacer este cambio
nos resultará un esfuerzo extremadamente costoso. Para solucionar el problema, debe-
mos hacer uso de estilos. Estos estilos trabajan de manera similar a las hojas de estilo
(CSS, Cascade Style Sheets) de HTML, donde podremos definir un comportamiento
visual general para los controles y aplicarlos a todos los controles que necesitemos. Así,
al modificar un estilo, es posible afectar a todos los controles que consuman de éste.
Lasplantillasomoldes,porotraparte,sonutilizadospararedefinirelcomportamiento,
como la apariencia visual sobre la base de un control inicial, pero la redefinición de la
apariencia visual va mucho más allá que la conseguida con estilos. Mientras que con
estilos podemos modificar las características tales como color, ancho, alto, o tipo
de fuente usada en el control, con las plantillas podremos hacer que, por ejemplo,
un botón no tenga la apariencia de un botón como tal, sino que, por el contrario,
se transforme en un círculo, en una imagen o en cualquier otro elemento que es-
té acorde a nuestras necesidades visuales.
Estilos
Luego de lo dicho anteriormente, veremos cómo modificar la apariencia visual de
los controles con la creación y aplicación de estilos a los controles ya existentes. Pa-
ra poder declarar un estilo, debemos seguir el siguiente patrón:
UserControl.Resources
Style x:Key=”Estilo1” TargetType=”TextBox”
...
/Style
/UserControl.Resources
Podemos ver que el estilo es declarado dentro de los recursos del tag UserControl
de la misma forma que hicimos con las animaciones y el tag Storyboard. Si bien
ésta es una opción, también podríamos declarar este estilo en los recursos globales
de toda la aplicación, colocándolo dentro del archivo App.xaml.
5. LUZ, CÁMARA, ACCIÓN
178
05_Silverlight.qxp 9/30/09 1:33 PM Page 178
Application.Resources
Style x:Key=”Estilo1” TargetType=”TextBox”
...
/Style
/Application.Resources
De esta forma, si tenemos más de una página XAML en nuestra aplicación, po-
dremos compartir el estilo entre ellas. Por otro lado, también vemos que aparecen
dos nuevos atributos en la declaración de un estilo.
• x:Key: este atributo es necesario para poder identificar el estilo creado. Consumi-
remos el estilo mediante este nombre.
• TargetType: tipo de control que podrá usar este estilo. Con este atributo, restringimos
el uso del estilo a un tipo de control. Es similar a la capacidad de ASP.net de gene-
rar estilos visuales para los controles, pudiendo crear estilos para tipos específicos.
Figura 17. Varios TextBox que consumen del mismo estilo.
Mover objetos
179
En la Web, podemos encontrar cientos de sitios con código de ejemplo para Silverlight 2. De cual-
quier manera, uno de los destacados es el sitio oficial de Silverlight, hasta el que podemos na-
vegar para descargar excelentes ejemplos. La dirección es http://silverlight.net.
CÓDIGO DE EJEMPLO
05_Silverlight.qxp 9/30/09 1:33 PM Page 179
Los estilos se aplican a cada una de las propiedades del objeto que queremos confi-
gurar. En el caso de la Figura 17, el estilo utilizado es el siguiente:
Style x:Key=”Estilo1” TargetType=”TextBox”
Setter Property=”Background”
Setter.Value
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FF88CAF0”/
GradientStop Color=”#FFFFFFFF” Offset=”1”/
/LinearGradientBrush
/Setter.Value
/Setter
Setter Property=”BorderBrush”
Setter.Value
LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0”
GradientStop Color=”#FFA3AEB9”/
GradientStop Color=”#FF9DBACE” Offset=”0.567”/
GradientStop Color=”#FF000000” Offset=”1”/
/LinearGradientBrush
/Setter.Value
/Setter
Setter Property=”Foreground” Value=”#FF342449”/
Setter Property=”BorderThickness” Value=”2,2,2,2”/
Setter Property=”MinHeight” Value=”25”/
Setter Property=”Text” Value=””/
/Style
Necesitamos colocar, por cada atributo por modificar, un tag Setter, el mismo que
especifica el nombre de la propiedad (Property) que se modificará y su valor (Value).
Es posible también especificar valores para tipos complejos mediante el uso de Setter.
Value, colocando dentro de éste la descripción del tipo complejo. Por último, debe-
remos aplicar el estilo al control que lo consumirá de la siguiente manera:
TextBox Height=”25” Width=”120” Style=”{StaticResource Estilo1}”/
Si colocamos los estilos dentro de la declaración del tag UserControl como den-
tro del tag Application, es posible reutilizarlos de forma global, aunque también
5. LUZ, CÁMARA, ACCIÓN
180
05_Silverlight.qxp 9/30/09 1:33 PM Page 180
pueden reducir el alcance de los estilos limitándolos al control en sí o a un con-
junto de controles contenidos por algún control contenedor.
En la Figura 18, el botón de la derecha está contenido por un control StackPanel,
que tiene declarado el estilo para el botón, estilo que sólo podrá ser consumido
por los controles contenidos por el StackPanel. La declaración del estilo en el
StackPanel es similar a la utilizada de manera global por el tag UserControl co-
mo el tag Application dentro del archivo App.xaml.
StackPanel Margin=”171,12,24,71”
StackPanel.Resources
Style x:Key=”EstiloContenido” TargetType=”Button”
Setter Property=”BorderThickness” Value=”2,2,2,2”/
Setter Property=”Background”
...
Figura 18. El botón de la derecha, contenido
por un StackPanel consumiendo el estilo declarado.
Mover objetos
181
RRR
Tratando de mantener concordancia entre desarrollos, los estilos poseen un comportamiento
similar a las máscaras usadas en ASP.net. Esto garantiza que los desarrolladores web puedan
fácilmente adaptarse a este modelo. Más información en http://msdn.microsoft.com/es-es,
buscando temas y máscaras.
EL ENFOQUE ASP.NET
05_Silverlight.qxp 9/30/09 1:33 PM Page 181
Plantillas
Si el estilo nos permitió modificar los valores, atributos y propiedades visuales
del control, las plantillas nos permitirán crear controles basándonos en otros y
alterar el aspecto de éstos. La ventaja significativa de las plantillas radica en que,
utilizando como raíz un control existente y pudiendo reusar sus eventos, podre-
mos crear uno nuevo. Pensemos en la capacidad de un botón de disparar un even-
to cuando el usuario lo presiona con el mouse. Esta capacidad no está presente
en todos los controles, por lo que podríamos reutilizarla creando nuestro propio
botón con un aspecto diferente del estándar. De esta forma, partiendo de un con-
trol inicial, construimos uno completamente nuevo.
Figura 19. Un nuevo botón construido sobre la base del control estándar.
Button HorizontalAlignment=”Left” Margin=”120,91,0,0”
VerticalAlignment=”Top” Content=”Hacer Click”
Button.Template
ControlTemplate TargetType=”Button”
5. LUZ, CÁMARA, ACCIÓN
182
RRR
Si hemos trabajado en el desarrollo web, específicamente en ASP.net, notaremos que el concepto
detrás de las plantillas resulta similar al de la creación de controles compuestos. Encontraremos
más información en http://msdn.microsoft.com/es-es, buscando control web compuesto.
SIMILITUDES
05_Silverlight.qxp 9/30/09 1:33 PM Page 182
Grid Height=”38” Width=”74”
Border Background=”#FFB0ECE8” BorderBrush=”#FF000000”
BorderThickness=”2,2,2,2” CornerRadius=”5,0,5,0”
TextBlock Text=”{TemplateBinding Content}”
TextWrapping=”Wrap” Margin=”3,3,3,3” HorizontalAlignment=”Center”
VerticalAlignment=”Center”/
/Border
/Grid
/ControlTemplate
/Button.Template
/Button
En el ejemplo, la plantilla se encuentra incrustada dentro del mismo control Button,
por lo que esta configuración sólo aplicará a este botón y no a otros que pudiéramos
adicionar al proyecto. También es posible ver la secuencia de controles usados para de-
finir el nuevo elemento. Primero el uso del control Border usado para definir el con-
torno del botón y redondear dos de las esquinas del objeto. Dentro de éste, un control
TextBlock utilizado para mostrar el texto del botón. Otro detalle es la aparición del va-
lor {TemplateBinding Content} dentro del atributo Text del control TextBlock. Este
valor asegura que el control TextBlock muestre el contenido de la misma propiedad
configurada en el control padre. Como el control Button posee un atributo llamado
Content, lo que se escriba en éste será transferido en forma automática al atributo
Text del control TextBlock. Podemos usar este tipo de enlazados con cualquier atribu-
to o propiedad presente en los elementos hijo y que pudieran ser configurados desde
el elemento padre. Como habremos notado, muchos controles en Silverlight poseen
efectos que se disparan cuando el usuario interactúa con ellos. Si el mouse pasa por
encima del control, éste presenta una superficie de un color especial o, si es deshabili-
tado, el control se muestra con otro color. Esto se debe a que, en su interior, estos con-
troles manejan animaciones basadas en distintos eventos por parte del usuario, por lo
que, al redefinir un control, es posible también modificar estas animaciones. Veamos
un ejemplo de las animaciones declaradas para el control Button personalizado.
Mover objetos
183
RRR
Es importante agregar el tag vsm:VisualState x:Name=”Normal”/ cuando trabajemos con ani-
maciones en las plantillas. Si hacemos esto, lograremos que, cuando el elemento modificado no
esté aplicando ninguna animación, el objeto vuelva, en forma automática, a su estado original.
RESTAURAR ESTADOS
05_Silverlight.qxp 9/30/09 1:33 PM Page 183
Button x:Name=”Boton1” VerticalAlignment=”Top” Content=”Hacer Click”
Margin=”114,40,127,0” Height=”50”
Button.Template
ControlTemplate TargetType=”Button”
Grid Width=”{TemplateBinding Width}” Height=”{TemplateBinding
Height}”
vsm:VisualStateManager.VisualStateGroups
vsm:VisualStateGroup x:Name=”EstadosComunes”
vsm:VisualState x:Name=”Normal”/
vsm:VisualState x:Name=”MouseOver”
Storyboard
DoubleAnimation From=”11” To=”16”
Duration=”0:0:0.2”
Storyboard.TargetName=”textInterno”
Storyboard.TargetProperty=”FontSize”
/DoubleAnimation
/Storyboard
/vsm:VisualState
/vsm:VisualStateGroup
/vsm:VisualStateManager.VisualStateGroups
Border Background=”#FFB0ECE8” BorderBrush=”#FF000000”
BorderThickness=”2,2,2,2” CornerRadius=”5,0,5,0”
Width=”{TemplateBinding Width}”
TextBlock x:Name=”textInterno” Text=”{TemplateBinding
Content}” TextWrapping=”NoWrap” Margin=”3,3,3,3”
HorizontalAlignment=”Center”
VerticalAlignment=”Center”
FontSize=”11”/
/Border
/Grid
/ControlTemplate
/Button.Template
/Button
En el código anterior, introdujimos algunos tags nuevos:
• vsm:VisualStateManager: este tag representa el contenedor de los diferentes
estados que puede contener el control. Dentro de éste, tenemos que agregar to-
dos los estados por los cuales reaccionará el control.
5. LUZ, CÁMARA, ACCIÓN
184
05_Silverlight.qxp 9/30/09 1:33 PM Page 184
• vsm:VisualStateGroup: este tag agrupa los estados en un contenedor común
bajo un nombre representativo.
• vsm:VisualState: representa un estado posible del control, además de contener
todas las animaciones que ese estado pueda representar.
Figura 20. Animaciones personalizadas en plantillas. A la izquierda, vemos el botón
en su estado normal y, a la derecha, el mismo botón una vez aplicada la animación.
De esta forma, las animaciones contenidas dentro del tag vsm:VisualState x:Name=
”MouseOver” se ejecutarán cuando el usuario posicione el mouse sobre el botón. La
animación, en este caso, agrandará el tamaño de la fuente del texto interno del botón.
Con estas características no sólo podemos modificar el control para que tenga el as-
pecto que nosotros queramos, sino que, además, es posible manipular los estados por
los cuales pasará nuestro control, pudiendo modificar su presentación y comporta-
miento acorde a cómo el usuario interactúe con él.
Mover objetos
185
… RESUMEN
En este capítulo aprendimos a manipular los distintos elementos de Silverlight de forma que
podamos quitarle rigidez a las aplicaciones que construyamos. Animaciones, transformacio-
nes y estilos para los controles, así como algunas técnicas para presentar mejor el contenido
y hacer más atractivas las interfaces con las que el usuario debe trabajar. En el próximo ca-
pítulo, nos introduciremos otro poco en características visuales como las DeepZoom, y nos
acercaremos más aún a los códigos C# y JavaScript.
05_Silverlight.qxp 9/30/09 1:33 PM Page 185
186

PREGUNTAS TEÓRICAS
1 ¿Cuántos tipos de transformaciones pode-
mos encontrar en Silverlight 2?
2 Si queremos especificar una transforma-
ción, ¿qué tag XAML debemos usar dentro
del objeto que va a ser modificado?
3 ¿Qué parámetros son necesarios para apli-
car una transformación de traslación?
4 ¿Cuál es la unidad utilizada en una trans-
formación de rotación?
5 Si necesitamos rotar un objeto mediante
una transformación de rotación, ¿siempre
debemos realizarlo desde el centro del
objeto? ¿Es posible modificar este punto
de rotación?
6 ¿Cuándo debemos usar la animación lla-
mada ColorAnimation?
7 ¿Cuál es el formato utilizado para especificar
el tiempo de duración de las animaciones?
8 ¿Qué debemos ejecutar desde código C#
para que una animación se inicie?
9 ¿Qué es un estilo en Silverlight 2?
10¿Para qué usamos plantillas en Silverlight 2?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Intente crear una animación, utilizando
ColorAnimation, para modificar el color de
fondo de un control en el momento en el
que el ratón se posicione sobre él.
2 Busque en Internet información sobre ani-
maciones cuadro a cuadro con Silverlight 2.
3 Busque animaciones xaml en http://msdn.
microsoft.com/es-es para aprender más
sobre transformaciones y animaciones con
Silverlight 2.
4 Ingrese en http://msdn.microsoft.com/
es-es y busque animaciones 3D avanzadas
para conocer más sobre simulaciones tri-
dimensionales con Silverlight 2 mediante
el uso de transformaciones y animaciones.
5 Ingrese en http://silverlight.net/learn/ y
allí busque 78708 para ver un video sobre
animaciones con Silverlight 2.
05_Silverlight.qxp 9/30/09 1:33 PM Page 186
Cerrar
el círculo
MediaElement 188
Ejecutar sonidos 188
Video 194
Elementos con video embebido 195
Marcadores de video 196
Deep Zoom 199
Crear el primer Deep Zoom 200
Incluir Deep Zoom
en Silverlight 203
Dibujar con InkPresenter 208
Dibujar en forma manual 212
Dibujar sobre otros elementos 215
InkPresenter y áreas
de dibujo 217
Resumen 219
Actividades 220
Capítulo 6
Este capítulo está dedicado a tratar tres
complementos de Silverlight. Y, si bien
los llamaremos complementos,
son tan importantes que merecen
un capítulo completo. Con éstos
podremos dibujar, transmitir videos
y hasta manipular imágenes de alta
definición de forma simple.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
06_Silverlight.qxp 9/30/09 1:33 PM Page 187
MEDIAELEMENT
En el capítulo 2, realizamos un proyecto Silverlight que implementaba el control
MediaElement para visualizar un video. Pero las características de este control pueden
ir mucho más lejos y, con esto, todo lo relacionado al manejo de video dentro de Sil-
verlight. Este control no tiene como único objetivo visualizar videos, ya que con él
podremos también ejecutar sonidos o hacer lo que se conoce como streaming (re-
producción de videos bajo demanda). Veamos, entonces, cómo extender las capaci-
dades de este control maximizando las potencialidades que presenta.
Ejecutar sonidos
Antes de utilizar el control MediaElement para ejecutar sonidos, debemos cono-
cer los formatos soportados. Si bien el control tiene pleno soporte para los for-
matos creados por Microsoft, como el WMA (Windows Media Audio), también
es posible consumir un formato más común como el MP3. A continuación, po-
demos ver todos los formatos soportados.
• WMA 7: Windows Media Audio 7.
• WMA 8: Windows Media Audio 8.
• WMA 9: Windows Media Audio 9.
• WMA 10: Windows Media Audio 10.
• MP3: ISO/MPEG Layer-3.
En nuestro proyecto, si queremos reproducir música o sonido, deberemos de-
clarar el control MediaElement de la siguiente forma:
Grid x:Name=”LayoutRoot” Background=”White”
MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3”
/MediaElement
/Grid
6. CERRAR EL CÍRCULO
188
RRR
Para acceder a un archivo, no deberemos usar rutas que incluyan identificadores tales como
C:DirectorioArchivo, sino que accederemos a los archivos como si se tratara de un recurso
web, utilizando sólo rutas relativas al punto de origen de la aplicación Silverlight.
RUTAS
06_Silverlight.qxp 9/30/09 1:33 PM Page 188
Debemos tener sumo cuidado al momento de colocar la ruta del recurso de soni-
do por reproducir, ya que se requiere de una ruta relativa a la posición donde se
encuentra el resultado de nuestra aplicación Silverlight. Esto quiere decir que, si el
archivo de sonido se encuentra a la misma altura en el árbol de directorios que
nuestra aplicación, sólo necesitaremos colocar el nombre del elemento que se re-
producirá. Pero, si éste está en alguna ruta más profunda, deberemos colocar la ruta
desde el punto inicial de nuestra aplicación en adelante. En el código anterior,
vemos que el sonido por reproducir se encuentra dentro de la carpeta Musica a par-
tir de la posición del archivo compilado, como se muestra en la siguiente figura.
Figura 1. Árbol de la solución con la estructura deseada.
El control MediaElement nos puede brindar información de lo que está reprodu-
ciendo, así como lo que está cargando desde alguna dirección. Tengamos en cuen-
ta que las pruebas que podamos hacer de forma local cargarán mucho más rápido
que si consumiéramos los archivos desde Internet. Por este motivo, debido a la
velocidad de carga, este control puede avisarnos el estado de ésta, así como la fi-
nalización de carga del archivo en cuestión, para poder presentar información al
MediaElement
189
RRR
Tanto sea de video como de sonido el archivo que estamos agregando a nuestro proyecto Silverlight,
debemos configurar éste para que sea copiado junto con el resultado de la aplicación cada vez
que la compilemos. Podemos conseguir esta acción seleccionando el archivo y modificando la
propiedad Copiar en el directorio de resultados, colocándola en Copiar siempre.
ADICIÓN DE ARCHIVOS
06_Silverlight.qxp 9/30/09 1:33 PM Page 189
usuario sobre estos estados. Si agregamos un control TextBlock, podremos brindar
información al usuario sobre el estado de reproducción del archivo.
Grid x:Name=”LayoutRoot” Background=”White”
TextBlock x:Name=”Tiempo” VerticalAlignment=”Top”
HorizontalAlignment=”Center”/TextBlock
MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3”
/MediaElement
/Grid
Luego, crearemos un temporizador que inspeccionará de manera continua el valor
de la propiedad Position del control MediaElement, y mostrará el progreso de la re-
producción del archivo en el TextBlock antes declarado.
DispatcherTimer reloj;
public Page()
{
InitializeComponent();
reloj = new DispatcherTimer();
reloj.Tick += new EventHandler(reloj_Tick);
reloj.Interval = TimeSpan.FromSeconds(0.1);
reloj.Start();
}
void reloj_Tick(object sender, EventArgs e)
{
this.Tiempo.Text = “Tiempo transcurrido: “ +
this.Musica.Position.TotalSeconds.ToString();
}
6. CERRAR EL CÍRCULO
190
_`
En los ejemplos usamos MP3 del álbum Ghost del grupo Nine Inch Nails. Este CD es provisto por
la banda de manera gratuita y es de libre uso y distribución. A pesar de esto, ha generado exce-
lentes ganancias. Este álbum puede ser descargado desde la página http://ghosts.nin.com.
MP3 GRATUITOS
06_Silverlight.qxp 9/30/09 1:33 PM Page 190
El resultado del código anterior podemos observarlo en la Figura 2, donde el conta-
dor se actualiza constantemente basado en el progreso de reproducción del archivo
MP3. Como vemos, el control MediaElement posee todas las características necesa-
rias para administrar estos tipos de archivos.
Figura 2. Aquí podemos ver la cantidad
de segundos transcurridos en la reproducción del archivo..
Es posible extender un poco más nuestro ejemplo para controlar con profundidad
la reproducción del archivo. Agreguemos algunos controles Slider, CheckBox y
Button para manipular la reproducción del archivo MP3.
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition/
RowDefinition/
RowDefinition/
RowDefinition/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition/
/Grid.ColumnDefinitions
TextBlock x:Name=”Tiempo” VerticalAlignment=”Bottom”
HorizontalAlignment=”Left” Grid.Row=”1” Margin=”123,0,0,13”/
MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3” Grid.Row=”1”
AutoPlay=”False” MediaOpened=”Musica_MediaOpened” /
MediaElement
191
06_Silverlight.qxp 9/30/09 1:33 PM Page 191
Button HorizontalAlignment=”Left” Margin=”105,8,0,0”
VerticalAlignment=”Top”
Grid.Row=”2” Content=”Reproducir” d:LayoutOverrides=”Height”
Click=”Button_Click”/
Button Margin=”184,8,162,0” VerticalAlignment=”Top” Grid.Row=”2”
Content=”Detener” d:LayoutOverrides=”Height”
Click=”Button_Click_1”/
Button HorizontalAlignment=”Right” Margin=”0,8,114,0”
VerticalAlignment=”Top” Grid.Row=”2” Content=”Parar”
d:LayoutOverrides=”Width, Height” Click=”Button_Click_2”/
CheckBox HorizontalAlignment=”Left” VerticalAlignment=”Bottom”
Content=”Silenciar” d:LayoutOverrides=”Height”
Click=”CheckBox_Click” x:Name=”Silencio”/
Slider Margin=”105,26,114,31” Grid.Row=”1”
d:LayoutOverrides=”Height” x:Name=”Progreso”
ValueChanged=”Progreso_ValueChanged”/
/Grid
Para cada acción o evento necesitamos crear su manejador en el código C#. Tam-
bién notaremos, en el siguiente código, que hemos asignado valores al control
Slider sobre la base de las características del archivo por reproducir.
DispatcherTimer reloj;
public Page()
{
InitializeComponent();
reloj = new DispatcherTimer();
reloj.Tick += new EventHandler(reloj_Tick);
reloj.Interval = TimeSpan.FromSeconds(0.1);
reloj.Start();
}
void reloj_Tick(object sender, EventArgs e)
{
this.Tiempo.Text = “Tiempo transcurrido: “ +
this.Musica.Position.TotalSeconds.ToString();
this.Progreso.Value = this.Musica.Position.TotalSeconds;
}
6. CERRAR EL CÍRCULO
192
06_Silverlight.qxp 9/30/09 1:33 PM Page 192
private void Musica_MediaOpened(object sender, RoutedEventArgs e)
{
this.Progreso.Maximum =
this.Musica.NaturalDuration.TimeSpan.TotalSeconds;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Musica.Play();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.Musica.Pause();
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
this.Musica.Stop();
}
private void Progreso_ValueChanged(object sender,
RoutedPropertyChangedEventArgsdouble e)
{
this.Musica.Position = TimeSpan.FromSeconds(this.Progreso.Value);
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
this.Musica.IsMuted = (bool)this.Silencio.IsChecked;
}
MediaElement
193
RRR
Microsoft pone nuestra disposición un sitio web en el que se enseñan técnicas avanzadas en el uso
del producto Microsoft Expression Blend. En este sitio, podremos aprender técnicas para optimi-
zar el uso de videos, la aplicación de efectos y movimiento sobre los objetos XAML y hasta la in-
terfaz de esta aplicación. En http://expression.microsoft.com buscamos Learn Expression Blend.
MÁS DE MICROSOFT EXPRESSION BLEND
06_Silverlight.qxp 9/30/09 1:33 PM Page 193
Figura 3. Nuestro reproductor de MP3 en el que podremos
iniciar, pausar y detener la reproducción, así como saltar a cualquier
posición del sonido, incluso, silenciarlo si es necesario.
Video
Iniciamos el capítulo con la reproducción de sonidos y música, ya que era un punto
pendiente si tenemos en cuenta el ejemplo creado en el capítulo 2. A pesar de esto, el
tratamiento de video con el control MediaElement tiene aún más que ofrecer. Si bien
no es competencia de este libro hablar de las características del streaming de videos des-
de servidores web, sí veremos cómo Silverlight nos brinda soporte para esto mediante
el control MediaElement, pudiendo aplicar el video sobre superficies, leer y reconocer
la información contenida en él, entre otras características. En la actualidad, el control
MediaElement soporta la reproducción de los siguientes formatos de video:
• WMV1: Windows Media Video 7.
• WMV2: Windows Media Video 8.
• WMV3: Windows Media Video 9.
• WMVA: Windows Media Video Advanced Profile, non-VC-1.
• WMVC1: Windows Media Video Advanced Profile, VC-1.
Como podemos notar, los formatos de video son los provistos por Microsoft y se
centran en el WMV (Windows Media Video). Por este motivo, es necesario con-
tar con algún convertidor de video a la hora de querer reproducir video con Sil-
verlight. Encontraremos variadas herramientas útiles para esto, como Windows
Movie Maker incluida en la mayoría de las versiones de Windows, o, dentro del
conjunto de herramientas Expression, Microsoft Expression Encoder 2.
6. CERRAR EL CÍRCULO
194
06_Silverlight.qxp 9/30/09 1:33 PM Page 194
Elementos con video embebido
Ya sabemos que XAML se basa en XML para representar los distintos elementos y,
por tal motivo, así como es posible en XML anidar elementos, también es posible
hacerlo con XAML. En el caso del video, podemos extender las funcionalidades de vi-
sualización mucho más allá de la simple representación de una película en un rectán-
gulo: es posible reproducir video dentro de otros elementos, los que actuarán como
una máscara. Así, si tenemos texto con un video dentro de éste, el video será visible
por sobre el texto, mostrando sólo las partes que comprendan la frase o palabras
de dicho elemento. Esta característica la conseguimos mediante el uso del elemen-
to VideoBrush, y podemos implementarlo como sigue.
MediaElement x:Name=”Video” Source=”SilverLightConMarcadores.wmv”
Width=”100” Height=”50” HorizontalAlignment=”Left”
Margin=”7.915,8,0,0”
VerticalAlignment=”Top”/
TextBlock HorizontalAlignment=”Left” Margin=”8.085,72,0,0”
VerticalAlignment=”Top” Width=”340.711” FontSize=”48”
Text=”Video en texto con SilverLight” TextWrapping=”Wrap”
FontWeight=”Bold” FontFamily=”Comic Sans MS”
TextBlock.Foreground
VideoBrush SourceName=”Video”/VideoBrush
/TextBlock.Foreground
/TextBlock
En el código anterior, creamos un elemento MediaElement para reproducir un video.
Esto es necesario para poder utilizar el tag VideoBrush, ya que éste necesita de un
componente con la capacidad de reproducción de video para visualizar ese video.
Pensemos en VideoBrush como la posibilidad de pintar en cualquier superficie lo
que el control MediaElement está reproduciendo en este momento. En este caso, el
video se pintará sobre el color de fondo del control TextBlock. Pero no sólo es po-
sible aplicarlo sobre este control ya que, como dijimos, VideoBrush es una forma de
MediaElement
195
RRR
Si bien la versión 2 de Silverlight puede resultar limitada en la cantidad de formatos posibles para
reproducción de video, la siguiente versión de Silverlight, Silverlight 3, contará con pleno soporte
para los formatos de video más conocidos, incluidos los utilizados por Adobe Flash y QuickTime.
FORMATOS DE VIDEO
06_Silverlight.qxp 9/30/09 1:33 PM Page 195
pintar un video sobre otros elementos, sino que podríamos aplicarlo sobre cualquier
otro control que posea propiedades de pintado. Como vemos en el siguiente códi-
go, pintamos el mismo video sobre la superficie de un control Button.
Button HorizontalAlignment=”Left” VerticalAlignment=”Bottom”
Content=”Button” Margin=”8.085,0,0,23” Height=”52” Width=”131”
Button.Background
VideoBrush SourceName=”Video”/VideoBrush
/Button.Background
/Button
Notemos que VideoBrush utiliza la propiedad SourceName para especificar el nombre
del control MediaElement desde donde obtendrá la fuente de video. Esto quiere de-
cir que todos los cambios que nosotros realicemos al control MediaElement también
afectarán a los elementos VideoBrush que pudiéramos tener en nuestra aplicación.
Figura 4. Video sobre diferentes objetos.
Marcadores de video
Cuando trabajamos con videos, existe la posibilidad de agregarles marcas con
identificaciones especiales. Estas marcas, en ocasiones, son usadas para hacer
avanzar el video hasta la marca en cuestión y darle la posibilidad al usuario de ele-
gir el punto para comenzar a visualizar el video.
El control MediaElement puede leer las marcas en los videos para otorgar la mis-
ma posibilidad, esto es, desplazar el video hasta el punto en el que se encuentre
esa marca. El primer paso para trabajar con marcadores es poder reconocerlos.
6. CERRAR EL CÍRCULO
196
06_Silverlight.qxp 9/30/09 1:33 PM Page 196
El control MediaElement posee un evento que nos avisará cada vez que pase por
un marcador. En el siguiente código, hacemos uso de este evento para mostrar
los marcadores incluidos en el video:
MediaElement Source=”SilverLightConMarcadores.wmv”
Width=”300” Margin=”50,25,50,84”
MarkerReached=”MediaElement_MarkerReached”/
TextBlock x:Name=”TextoMarcas” VerticalAlignment=”Bottom” Text=””
TextWrapping=”Wrap” Margin=”8,0,8,8” Height=”59”/
Cada vez que se pase por un marcador, se disparará el evento MarkerReached, escri-
biendo la descripción y la posición de tiempo en la que se encuentra esta marca.
private void MediaElement_MarkerReached(object sender,
TimelineMarkerRoutedEventArgs e)
{
this.TextoMarcas.Text = “Nombre del marcador: “ + e.Marker.Text +
“, encontrado en “ + e.Marker.Time.Minutes.ToString() +
“:” + e.Marker.Time.Seconds.ToString();
}
En la figura que aparece a continuación, podemos ver cómo se despliega la mar-
ca del video en el momento de alcanzarla.
Figura 5. Marca alcanzada mientras se reproduce el video.
MediaElement
197
06_Silverlight.qxp 9/30/09 1:33 PM Page 197
Ya que podemos detectar cada marca, sería sencillo reconocer todos los marcadores
de un video para presentárselos al usuario y que éste pueda saltar entre ellos y así
navegar con mayor facilidad dentro de la reproducción en curso.
TimelineMarker miMarcador;
private void MediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
miMarcador = this.Video.Markers[0];
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Video.Position = miMarcador.Time;
this.Video.Play();
}
Vemos, en el código anterior, que en el evento MediaOpened, disparado en el momen-
to en que el video es cargado totalmente, leemos los marcadores. Si bien éstos pueden
ser una lista, sólo tomaremos el primero que encontramos, almacenándolo en un ob-
jeto del tipo TimelineMarker. Luego, por medio del evento Click de un botón, usamos
el valor de tiempo de este marcador para reposicionar la reproducción del video. Co-
mo vemos a continuación, al presionar el botón, el video vuelve al punto de la marca.
Figura 6. A la izquierda, el video retrocedió hasta
la marca. A la derecha, el video se ejecuta de manera continua.
6. CERRAR EL CÍRCULO
198
06_Silverlight.qxp 9/30/09 1:33 PM Page 198
MediaElement tiene aún mucho más por ofrecer y, por esto, iremos develando sus
características en los siguientes capítulos. De cualquier manera, en este punto nos
habremos dado cuenta de que la potencia de Silverlight y el manejo de elementos
multimedios no son una limitación, sino que, por el contrario, pueden darnos mu-
chas ventajas en el desarrollo de aplicaciones.
DEEP ZOOM
El concepto de Deep Zoom es el de proveer una herramienta para manipular
imágenes de gran tamaño dentro de las aplicaciones Silverlight, con el objetivo
de aligerar la transmisión de ellas al cliente. Además de esto, permite agregar fun-
cionalidades de acercamiento gradual o zoom. Pensemos en Deep Zoom como
en una técnica que despliega imágenes para el cliente, quien puede acercarse y ob-
servar los detalles de estas imágenes sobre la base de su resolución. Así, si conta-
mos con imágenes de alta definición, que por lo general son de varios megabytes,
transmitiremos toda la imagen con el máximo de sus detalles según la demanda
de información que el cliente requiera, sin tener que mover toda la imagen hasta
el cliente desde el principio, lo que significaría lentitud en la carga de la aplica-
ción y un elevado consumo de recursos para la transmisión de los datos.
Si bien existe en el mercado este tipo de tecnología y no podríamos decir que es
nueva, Deep Zoom marca una diferencia en la forma en cómo es presentada la
información. Esto se debe a que, en lugar de mostrar diferentes imágenes basadas
en el grado de zoom que realicemos, Deep Zoom transmitirá la imagen actual de
acuerdo con el rango de visión, con la mejor resolución posible, haciendo un ba-
lance entre calidad y costo de la transmisión de información hacia el cliente. De
esta forma, no veremos saltos entre cada uno de los grados de zoom y siempre ob-
tendremos una imagen de alta calidad obtenida desde la imagen original.
Si queremos empezar a trabajar con Deep Zoom, necesitaremos descargar la aplicación
Deep Zoom Composer desde el sitio web de Microsoft. Deep Zoom Composer no
tienen ningún costo asociado, por lo que podremos descargarlo y usarlo libremente.
Deep Zoom
199
_`
Hard Rock Cafe fue uno de los primeros sitios en utilizar la tecnología Deep Zoom. La empresa
lo implementó en su web para que los usuarios pudieran ver la colección de objetos, cartas, ins-
trumentos y otros elementos que poseen y que fueran entregados por diferentes artistas de la
música. Podemos ver el sitio de Memorabilia en http://memorabilia.hardrock.com.
UNO DE LOS PRIMEROS DEEP ZOOM
06_Silverlight.qxp 9/30/09 1:33 PM Page 199
Crear el primer Deep Zoom
Para crear un componente Deep Zoom, necesitamos una o varias imágenes, preferen-
temente de alta definición, y haber instalado la aplicación Deep Zoom Composer. Una
vez que consigamos esto, el primer paso es crear una aplicación nueva.
Figura 7. Creación de un nuevo proyecto con Deep Zoom Composer.
Hasta la fecha, Deep Zoom Composer sólo se encuentra disponible en idioma inglés.
A pesar de esto, su uso resulta simple e intuitivo, por lo que no tendremos problemas
en entender los pasos de la creación de este tipo de proyectos. Entonces, presionamos
sobre la opción New Project…. Al hacerlo, veremos la ventana para la creación del nue-
vo proyecto, donde introduciremos su nombre y la ruta física donde se alojará. Con el
proyecto creado, necesitamos completar tres pasos antes de obtener el producto final.
El primero es la importación de imágenes a partir del botón Import, ubicado en la
parte superior. Podremos importar tantas como necesitemos y, si bien uno de los pa-
sos es acomodar estas imágenes según cómo queramos que se visualicen, es recomen-
dable, en caso de tener múltiples imágenes que juntas formen una sola, utilizar otras
herramientas externas de composición de imágenes para unirlas en una, ya que Deep
Zoom Composer sólo nos proveerá de elementos básicos para hacer este trabajo. Una
vez adicionadas las imágenes, éstas aparecerán en la lista de la derecha.
6. CERRAR EL CÍRCULO
200
RRR
Tenemos la posibilidad de descargar DeepZoom Composer desde el sitio de descargas de Mi-
crosoft (www.microsoft.com/downloads). Allí, podremos acceder a la descarga realizando una
búsqueda con el nombre de la aplicación dentro del sitio web de Microsoft.
DEEP ZOOM COMPOSER
06_Silverlight.qxp 9/30/09 1:33 PM Page 200
Figura 8. En este caso, adicionamos una imagen al proyecto.
El siguiente paso de nuestro trabajo consiste en la composición de las imágenes
y cómo estarán distribuidas en las aplicación Deep Zoom. Presionando en el bo-
tón Compose, ubicado en la parte superior de Deep Zoom Composer, accedere-
mos al siguiente paso. Arrastrando las imágenes al lienzo de trabajo, colocaremos
cada una de ellas en la posición en la que queremos que se visualicen, como se
muestra en la figura que aparece a continuación.
Figura 9. Una imagen ubicada en el centro de Deep Zoom.
Deep Zoom
201
06_Silverlight.qxp 9/30/09 1:34 PM Page 201
El último paso consiste en generar el proyecto exportándolo al formato que pueda en-
tender Silverlight. Para esto, presionamos sobre la última opción de las tres superio-
res, llamada Export. Al hacer esto, tendremos que elegir el formato de exportación del
proyecto. Si necesitamos ver un ejemplo completo de la implementación de Deep
Zoom basado en nuestro proyecto, podremos elegir la opción Silverlight Deep Zoom.
Ésta creará un proyecto completo Silverlight que incluya botones para realizar zooms
y movimientos sobre las imágenes incluidas en él. Si, por el contrario, tenemos cierta
experiencia en la inclusión del resultado de Deep Zoom Composer en aplicaciones
Silverlight, elegiremos la opción Images para que la aplicación cree sólo los archivos
necesarios para que incluyamos, por nuestra cuenta, el proyecto Deep Zoom en nues-
tra aplicación Silverlight. También es posible elegir la calidad de la representación de
las imágenes que se van a mostrar. En la Figura 10, en la parte inferior derecha, vemos
las opciones de compresión de imagen. Esta compresión modifica el resultado de las
imágenes del archivo Deep Zoom resultante. Modificar estos valores podría acelerar
el proceso de descarga de las imágenes hacia el cliente, pero al mismo tiempo, un al-
to nivel de compresión podría deteriorar la calidad de las imágenes.
Figura 10. Vista final de Deep Zoom Composer para la exportación del proyecto.
Una vez que el proyecto fue generado y, dependiendo de las opciones que hubiéra-
mos elegido para generarlo, se nos presentará la opción de acceder al resultado. Es-
ta opción nos llevará a la carpeta con los resultados del proyecto. El proyecto en sí
es representado por un conjunto de archivos entre los que se encuentran los dife-
rentes muestreos de imágenes relacionados con las imágenes utilizadas para crear el
proyecto Deep Zoom, además de archivos XML con meta datos.
6. CERRAR EL CÍRCULO
202
06_Silverlight.qxp 9/30/09 1:34 PM Page 202
Figura 11. Resultado del proyecto Deep Zoom.
Incluir Deep Zoom en Silverlight
Para incrustar el resultado del proyecto Deep Zoom en Silverlight, crearemos un
nuevo proyecto Silverlight seleccionando la opción para que Visual Studio 2008
cree un sitio web adicional para ejecutar el proyecto (podemos recurrir al capítulo 3
para recordar este paso). Una vez creado, deberemos ver el árbol de la solución.
Figura 12. Proyecto Silverlight junto a un proyecto web para depuración.
Notaremos que el proyecto web contiene una carpeta llamada ClientBin. Esta car-
peta es la contenedora de los resultados que obtenemos luego de la compilación
Deep Zoom
203
06_Silverlight.qxp 9/30/09 1:34 PM Page 203
de la aplicación Silverlight y es el lugar donde se ubicará físicamente nuestra apli-
cación. Por eso, para tener acceso al contenido del proyecto Deep Zoom, allí ten-
dremos que colocar todos los archivos resultantes de Deep Zoom. Podemos ver
un ejemplo de esta acción en la siguiente figura.
Figura 13. En el árbol de soluciones, vemos los archivos del proyecto Deep Zoom.
Una vez que tenemos los archivos en su lugar, usaremos el control MultiScaleImage
para desplegarlas en el proyecto. Podemos ver un ejemplo a continuación.
UserControl x:Class=”Capitulo6MiDeepZoom.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”
MultiScaleImage x:Name=”MiDeepZoom” Width=”350” Height=”250”
Source=”mideepzoom/dzc_output.xml”/MultiScaleImage
/Grid
/UserControl
Observemos que el motivo por el que colocamos el proyecto Deep Zoom dentro de
la misma carpeta donde se despliega el resultado de la aplicación Silverlight es para
que resulte más simple poder accederla. También es importante el archivo al cual
se hace referencia, que es dzc_output.xml, archivo que contiene los metadatos del
proyecto, como lista de imágenes y direcciones, entre otros.
6. CERRAR EL CÍRCULO
204
06_Silverlight.qxp 9/30/09 1:34 PM Page 204
El paso que hicimos sólo mostrará el proyecto si desplegamos el estado inicial que hu-
biéramos configurado en el momento de crear el proyecto en Deep Zoom Composer.
Necesitaremos hacer algo de código para crear la interacción con las imágenes y que el
comportamiento de Deep Zoom se haga presente. Primero, modificaremos un poco el
código XAML para incluir llamadas a los eventos que se relacionan con el mouse.
Grid x:Name=”LayoutRoot” Background=”White”
MouseMove=”LayoutRoot_MouseMove”
MouseLeftButtonDown=”LayoutRoot_MouseLeftButtonDown”
MouseLeftButtonUp=”LayoutRoot_MouseLeftButtonUp”
MultiScaleImage x:Name=”MiDeepZoom” Width=”350” Height=”250”
Source=”mideepzoom/dzc_output.xml”
MouseLeave=”MiDeepZoom_MouseLeave”/MultiScaleImage
/Grid
Estos eventos se dispararán cuando el botón izquierdo del ratón sea presionado,
cuando se mueva e, incluso, cuando deje la zona en la que se está presentando el
proyecto Deep Zoom. Cada uno de estos eventos tendrá el código asociado co-
mo podemos ver a continuación:
private bool RatonPresionado;
private bool RatonArrastrando;
private Point UltimaPosicionRaton;
private Point DesfaseArrastre;
private Point PosicionActual;
private double FactorZoom;
private void MiDeepZoom_MouseLeave(object sender, MouseEventArgs e)
{
RatonArrastrando = false;
}
private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
{
if (RatonPresionado)
{
RatonArrastrando = true;
}
this.UltimaPosicionRaton = e.GetPosition(this.MiDeepZoom);
Deep Zoom
205
06_Silverlight.qxp 9/30/09 1:34 PM Page 205
if (RatonArrastrando)
{
Point newOrigin = new Point();
newOrigin.X = PosicionActual.X - (((e.GetPosition(MiDeepZoom).X -
DesfaseArrastre.X) / MiDeepZoom.ActualWidth) *
MiDeepZoom.ViewportWidth);
newOrigin.Y = PosicionActual.Y - (((e.GetPosition(MiDeepZoom).Y -
DesfaseArrastre.Y) / MiDeepZoom.ActualHeight) *
MiDeepZoom.ViewportWidth);
MiDeepZoom.ViewportOrigin = newOrigin;
}
}
private void LayoutRoot_MouseLeftButtonDown(object sender,
MouseButtonEventArgs e)
{
RatonPresionado = true;
RatonArrastrando = false;
DesfaseArrastre = e.GetPosition(this);
PosicionActual = MiDeepZoom.ViewportOrigin;
}
private void LayoutRoot_MouseLeftButtonUp(object sender,
MouseButtonEventArgs e)
{
RatonPresionado = false;
if (RatonArrastrando == false)
{
bool shiftApretado = (Keyboard.Modifiers  ModifierKeys.Shift) ==
ModifierKeys.Shift;
FactorZoom = 2.0;
6. CERRAR EL CÍRCULO
206
RRR
Si necesitamos saber cómo manejar la rueda del mouse para realizar zoom, podemos generar
un proyecto Deep Zoom con Deep Zoom Composer, que también genere un proyecto Silverlight
para incluir el resultado de Deep Zoom. El código generado por Deep Zoom Composer nos otor-
gará excelente código de ejemplo para nuestras implementaciones.
MANEJO DE LA RUEDA DEL MOUSE
06_Silverlight.qxp 9/30/09 1:34 PM Page 206
if (shiftApretado) FactorZoom = 0.5;
Zoom(FactorZoom, this.UltimaPosicionRaton);
}
RatonArrastrando = false;
}
public void Zoom(double zoom, Point pointToZoom)
{
Point puntoLogico = this.MiDeepZoom.ElementToLogicalPoint(pointToZoom);
this.MiDeepZoom.ZoomAboutLogicalPoint(zoom, puntoLogico.X,
puntoLogico.Y);
}
El código anterior puede resultar confuso a primera vista, pero todo se reduce al
método ZoomAboutLogicalPoint provisto por el control MultiScaleImage. Este mé-
todo es el encargado de generar el efecto de zoom basado en un factor de zoom,
tanto positivo como negativo, así como sobre la base de un punto XY. Este mé-
todo se ejecuta en el método Zoom del código anterior, ya que las demás líneas
de código se encargan de administrar el estado del mouse antes de realizar algu-
na acción. Si ejecutamos el proyecto, veremos que al presionar sobre la imagen
se realizará el acercamiento a ella, mientras que si lo hacemos presionando la te-
cla SHIFT (mayúsculas) al mismo tiempo que pulsamos el botón del mouse, la
imagen se alejará. A continuación, un ejemplo.
Figura 14. Observamos, en cada navegador,
el resultado de interactuar con la aplicación Deep Zoom.
Deep Zoom
207
06_Silverlight.qxp 9/30/09 1:34 PM Page 207
DIBUJAR CON INKPRESENTER
Silverlight trae consigo otros complementos, en especial, interesantes. Uno de estos
es InkPresenter, un componente que facilita la escritura manual sobre cualquier
aplicación Silverlight. Si bien el modelo de escritura a mano puede estar ligado con
los dispositivos móviles inteligentes como Pocket PCs o Tablet PCs, Silverlight
incorpora esta capacidad también, pudiendo enriquecer aún más el conjunto de fun-
cionalidades ofrecidas hasta el momento. Existen casos dentro del desarrollo de apli-
caciones empresariales donde puede ser necesario el reconocimiento de firmas
electrónicas, que son almacenadas en bases de datos y comparadas luego para su va-
lidación. También podría ser interesante brindarle al usuario la posibilidad de
enviar tarjetas electrónicas escritas por él, dejando de lado el texto plano automati-
zado que, por lo común, suele emplearse para este tipo de aplicaciones.
Entonces, InkPresenter es un control en Silverlight que nos otorgará una superfi-
cie de dibujado a mano haciendo uso del mouse, donde podremos capturar lo es-
crito, almacenarlo y procesarlo para su posterior uso. Además, InkPresenter viene
acompañado de un conjunto de APIs (Application Programming Interfaces o en cas-
tellano, interfaz para programación de aplicaciones) para el reconocimiento de los
patrones introducidos por el usuario y su transformación en texto plano legible.
Veamos la declaración de un elemento InkPresenter desde código XAML.
InkPresenter/InkPresenter
El tag XAML del control InkPresenter agregará el lienzo de dibujo a nuestra apli-
cación, y sólo podremos dibujar sobre él. Por este motivo, el control InkPresenter
deberá estar declarado por encima de cualquier otro elemento. Si algún otro com-
ponente se dibujara sobre el control InkPresenter, no podríamos visualizarlo y tam-
poco escribir sobre él, ya que los eventos relacionados con la captura de información
no serían alcanzados. Para entender esto, pensemos en capas u hojas de dibujo.
La capa superior y visible, la más cercana al usuario, es la que puede interactuar con
él, capturando cualquier tipo de acción que el usuario realice, dejando a las capas
6. CERRAR EL CÍRCULO
208
RRR
Los tipos de datos para colores en XAML son representados en formato hexadecimal, de ma-
nera similar al utilizado en HTML, con la diferencia de que, en Silverlight, se incluye un par de
números iniciales para especificar el nivel de transparencia de ese color. Si contamos con
#FF000000, obtenemos un color negro pleno y sin transparencias.
COLORES
06_Silverlight.qxp 9/30/09 1:34 PM Page 208
inferiores fuera del alcance de estos eventos. Por eso, deberemos asegurarnos de que
el control InkPresenter se posicione sobre la capa superior y más cercana al usuario.
Veamos, ahora, la declaración completa del control InkPresenter.
Grid x:Name=”LayoutRoot” Background=”White”
InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4”
Margin=”8,8,8,8”
Opacity=”1”
MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown”
MouseMove=”inkPresenter_MouseMove”
LostMouseCapture=”inkPresenter_LostMouseCapture”/
/Grid
Figura 15. Podemos ver el lienzo de InkPresenter incorporado en nuestro proyecto.
Del código anterior, los atributos destacables son los tres eventos relacionados
con la acción de escritura. A continuación, veamos sus detalles:
• MouseLeftButtonDown: este evento se refiere al momento en el que el usuario pre-
siona el botón izquierdo del mouse. En este evento, inicializaremos la captura de
información del control InkPresenter.
• MouseMove: cada vez que el usuario mueva el mouse sobre el lienzo de InkPresenter,
este evento se disparará. Al dispararse, guardaremos la información capturada pa-
ra que sea mostrada en el lienzo.
• LostMouseCapture: en el momento en que el botón del mouse sea liberado o el con-
trol deje de percibir información desde el usuario, este evento será disparado.
Dibujar con InkPresenter
209
06_Silverlight.qxp 9/30/09 1:34 PM Page 209
Figura 16. Aquí, podemos ver el control InkPresenter en acción.
Antes de comenzar a crear código para poder dibujar sobre InkPresenter, es ne-
cesario configurar los límites de dibujo ya que, si bien el control representa un
elemento rectangular, podemos especificar los espacios donde se podrá escribir o
no. Esto puede resultar muy versátil cuando necesitamos adaptar las caracterís-
ticas de dibujo a una zona en particular.
public Page()
{
InitializeComponent();
Limites();
}
private void Limites()
{
RectangleGeometry Rectangulo = new RectangleGeometry();
Rectangulo.Rect = new Rect(0, 0, this.inkPresenter.Width,
this.inkPresenter.Height);
this.inkPresenter.Clip = Rectangulo;
}
Los límites elegidos en este caso son representados por un rectángulo con el mis-
mo tamaño que el control InkPresenter. Esto hará que podamos escribir sobre
toda la superficie del control libremente. El siguiente paso es escribir el código
detrás de cada uno de los eventos antes mencionados.
6. CERRAR EL CÍRCULO
210
06_Silverlight.qxp 9/30/09 1:34 PM Page 210
private Stroke pincel;
private void inkPresenter_MouseLeftButtonDown(object sender,
MouseButtonEventArgs e)
{
this.inkPresenter.CaptureMouse();
StylusPointCollection ColeccionDeEstilos = new StylusPointCollection();
ColeccionDeEstilos.Add(e.StylusDevice.GetStylusPoints(this.inkPresenter));
pincel = new Stroke(ColeccionDeEstilos);
this.inkPresenter.Strokes.Add(pincel);
}
Dentro del código anterior, en el evento MouseLeftButtonDown, iniciamos la cap-
tura del mouse, además de configurar el tipo de pincel que se va a utilizar para
realizar el dibujo. Por defecto, este pincel será básico y de color negro. Por su
parte, el segundo evento se encargará de analizar las coordenadas del mouse a
medida que éste se desplaza por el control.
private void inkPresenter_MouseMove(object sender, MouseEventArgs e)
{
if (pincel != null)
pincel.StylusPoints.Add(e.StylusDevice.GetStylusPoints(this.inkPresenter));
}
Como vemos en este código, es necesario verificar que el pincel haya sido crea-
do antes de capturar los trazos generados por el mouse. Si no hiciéramos esto, el
usuario, al mover el mouse, crearía trazos continuos. Por último, incorporamos
el código relacionado al último evento.
private void inkPresenter_LostMouseCapture(object sender, MouseEventArgs e)
{
pincel = null;
}
Una vez que el botón del mouse es liberado, el pincel se elimina, haciendo que ya
no se dibujen los movimientos del usuario sobre el control.
Dibujar con InkPresenter
211
06_Silverlight.qxp 9/30/09 1:34 PM Page 211
Dibujar en forma manual
Como ya dijimos, InkPresenter representa trazos creados por el usuario. Estos
trazos no sólo pueden ser introducidos por el usuario, sino que es posible que
nosotros proveamos estos elementos desde el comienzo. La realización de este
trabajo nos lleva a la posibilidad de guardar información de trazos generados por
el usuario y, luego, mostrarlos sin intervención de su parte.
Figura 17. Trazos creados con XAML.
Como vemos en la figura anterior, el control InkPresenter puede mostrar trazos ba-
sados en tags creados de manera manual. Veamos, a continuación, el código XAML:
...
...
InkPresenter.Strokes
StrokeCollection
Stroke
Stroke.DrawingAttributes
DrawingAttributes Color=”#FF000000” Width=”5”
Height=”5” /
/Stroke.DrawingAttributes
Stroke.StylusPoints
StylusPoint X=”10” Y=”10” /
StylusPoint X=”100” Y=”10” /
6. CERRAR EL CÍRCULO
212
06_Silverlight.qxp 9/30/09 1:34 PM Page 212
StylusPoint X=”100” Y=”100” /
StylusPoint X=”10” Y=”100” /
StylusPoint X=”10” Y=”10” /
/Stroke.StylusPoints
/Stroke
/StrokeCollection
/InkPresenter.Strokes
/InkPresenter
Cada tag Stroke dentro del tag StrokeCollection representa un trazo único. Esto
es el equivalente a que el usuario hubiera creado dicho trazo sin dejar de presionar el
botón del mouse. El tag Stroke.DrawingAttributes representa la característica del
trazado. En el ejemplo, éste muestra un grosor de 5 pixeles de ancho y 5 pixeles de
alto, además de ser de color negro. Por último, encontramos cada uno de los puntos
del trazo representados por la colección Stroke.StylusPoints, que contendrá cada
uno de los puntos basados en el tag StylusPoint, el cual especifica las coordenadas
XY donde se inicia el punto. Debido a que éste es un único trazo, al dibujar más
puntos en diferentes coordenadas, éstos se uniránmediante una línea. Como vemos
en la Figura 17, la unión de los puntos derivó en la construcción de un cuadrado. Y
así como creamos trazos desde el código XAML, también podemos hacerlo desde
nuestro código, como observamos en la Figura 18. Allí, la línea de color verde es cre-
ada desde el código XAML. Esto se logra siguiendo el mismo patrón que el de XAML.
El siguiente código muestra cómo generar estos trazos desde código C#.
Figura 18. Trazos creados por código.
Dibujar con InkPresenter
213
06_Silverlight.qxp 9/30/09 1:34 PM Page 213
private void Button_Click(object sender, RoutedEventArgs e)
{
Stroke trazo = new Stroke();
trazo.DrawingAttributes.Width = 3;
trazo.DrawingAttributes.Height = 3;
trazo.DrawingAttributes.Color = Color.FromArgb(150, 50, 150, 150);
StylusPointCollection coleccionEstilos = new StylusPointCollection();
StylusPoint punto = new StylusPoint();
punto.X = 150;
punto.Y = 10;
coleccionEstilos.Add(punto);
StylusPoint punto2 = new StylusPoint();
punto2.X = 300;
punto2.Y = 10;
coleccionEstilos.Add(punto2);
StylusPoint punto3 = new StylusPoint();
punto3.X = 300;
punto3.Y = 100;
coleccionEstilos.Add(punto3);
trazo.StylusPoints.Add(coleccionEstilos);
this.inkPresenter.Strokes.Add(trazo);
}
Si comparamos el patrón XAML con el código antes presentado, notaremos sus
similitudes. Primero se crea el trazo, especificando el color y el grosor que tendrá.
Stroke trazo = new Stroke();
trazo.DrawingAttributes.Width = 3;
trazo.DrawingAttributes.Height = 3;
trazo.DrawingAttributes.Color = Color.FromArgb(150, 50, 150, 150);
...
...
Luego, creamos el contenedor de la colección de puntos por dibujar y adiciona-
mos cada uno de los puntos, como vemos en el siguiente código:
6. CERRAR EL CÍRCULO
214
06_Silverlight.qxp 9/30/09 1:34 PM Page 214
...
StylusPointCollection coleccionEstilos = new StylusPointCollection();
StylusPoint punto = new StylusPoint();
punto.X = 150;
punto.Y = 10;
coleccionEstilos.Add(punto);
...
Dibujar sobre otros elementos
Si seguimos el mismo modelo de dibujo sobre el elemento InkPresenter, veremos
que es posible extenderlo para que podamos dibujar sobre cualquier otro control
que deseemos. Esto resulta especialmente útil sobre controles y componentes con
capacidades de desplegar imágenes y videos.
Figura 19. Es posible dibujar sobre una imagen preestablecida.
El control InkPresenter puede contener otros controles, por lo que, para lograr
lo visto en la figura anterior, tendremos que agregar el control Image como con-
tenido del control InkPresenter. Veamos cómo hacerlo:
InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4”
Margin=”8,8,8,8” Opacity=”1”
Width=”384” Height=”284”
Dibujar con InkPresenter
215
06_Silverlight.qxp 9/30/09 1:34 PM Page 215
MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown”
MouseMove=”inkPresenter_MouseMove”
LostMouseCapture=”inkPresenter_LostMouseCapture”
Image Source=”Colinas azules.jpg” Width=”384” Height=”284”/
/InkPresenter
Luego, podremos intercambiar este elemento interno por cualquier otro capaz
de representar algún medio visual. El código para escribir sobre video resultará
similar al anterior. En este caso, utilizamos un control MediaElement para des-
plegar el video y escribir sobre él. En la Figura 20 que encontramos debajo pode-
mos ver un ejemplo del resultado que se podría obtener.
InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4”
Margin=”8,8,8,8” Opacity=”1”
Width=”384” Height=”284”
MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown”
MouseMove=”inkPresenter_MouseMove”
LostMouseCapture=”inkPresenter_LostMouseCapture”
MediaElement Source=”silverlight.wmv” AutoPlay=”True” /
/InkPresenter
Figura 20. En este caso, utilizamos el mismo
concepto para escribir sobre video.
6. CERRAR EL CÍRCULO
216
06_Silverlight.qxp 9/30/09 1:34 PM Page 216
InkPresenter y áreas de dibujo
Si bien el control InkPresenter se muestra, por lo general, como un rectángulo, re-
sulta lo bastante versátil como para poder definir áreas permitidas para dibujar so-
bre él. En este caso, el control InkPresenter aparecerá con bordes redondeados, y los
trazos realizados por el usuario no podrán sobrepasar estos límites. Para conseguir
esto, podemos hacer uso de la propiedad Clip del control. Lo haremos de la misma
forma que hemos empleado para asignar un área rectangular, pero, en este caso, es-
pecificaremos una matriz de puntos que representen las esquinas curvas.
InkPresenter x:Name=”inkPresenter”
Width=”300” Height=”200” Background=”Aqua”
MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown”
MouseMove=”inkPresenter_MouseMove”
LostMouseCapture=”inkPresenter_LostMouseCapture”
Clip=”M0.5,25.5 C0.5,11.692881 11.692881,0.5 25.5,0.5 L267,0.5
C280.80713,0.5 299,19.192881 299,33 L299,169 C299,182.80713 289.80713,201
276,201 L29,201 C15.192881,201 0.5,186.80713 0.5,173 z” /
Figura 21. Aquí podemos ver cómo, al intentar dibujar
por sobre las esquinas curvas, la línea de dibujo no es representada.
Si bien los valores introducidos en la propiedad Clip pueden resultar complejos de en-
tender y de crear en forma manual, Expression Blend 2 nos otorga herramientas para
hacerlo de manera visual y más simple. Allí, creamos el contorno que vamos a aplicar,
y luego copiamos y pegamos el resultado en el control InkPresenter. Primero debere-
mos agregar un elemento de dibujo al lienzo. Podremos usar elipses o rectángulos. Una
Dibujar con InkPresenter
217
06_Silverlight.qxp 9/30/09 1:34 PM Page 217
vez agregado el elemento, deberemos transformarlo a un tipo de elemento de traza-
do. Para conseguir esto, presionamos el botón izquierdo del mouse sobre el elemento
de dibujo, para seleccionar la opción Convertir en trazado dentro de Trazado.
Figura 22. Convirtiendo la elipse a un trazado.
Luego de convertir el elemento a trazado, es posible deformarlo a gusto para conseguir
la forma que queramos. Por último, aplicaremos este trazado al control InkPresenter.
Figura 23. El trazado completamente modificado.
Para aplicar el trazado, copiaremos el valor del atributo Data del trazado al atributo
Clip de InkPresenter. Como resultado, en este caso obtendremos el siguiente código:
6. CERRAR EL CÍRCULO
218
06_Silverlight.qxp 9/30/09 1:34 PM Page 218
InkPresenter x:Name=”inkPresenter”
Width=”300” Height=”250” Background=”Aqua”
MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown”
MouseMove=”inkPresenter_MouseMove”
LostMouseCapture=”inkPresenter_LostMouseCapture”
Clip=”M289.97556,99.001045 C255.73196,134.51219 198.63127,225.33125
119.70698,220.46407 C73.678635,217.62555 -25.515903,142.05704
16.996023,143.14827 C35.799923,143.63094 25.502108,94.232025
33.899151,74.349686 C49.08622,38.390076 115.76089,-10.094691
156.73918,49.198044 C206.78326,121.60835 319.49466,68.389313
289.97556,99.001045 z” /
Figura 24. El trazo de dibujo sólo se aplicará
a las zonas preestablecidas en la propiedad Clip.
Dibujar con InkPresenter
219
… RESUMEN
Videos, imágenes escalables y capacidades de dibujo; herramientas de Silverlight que pueden
enriquecer nuestras aplicaciones de una forma inmensurable. Si los controles y componentes,
junto a sus capacidades vistas en capítulos anteriores, no nos habían despertado aún la imagi-
nación, poder manipular imágenes de alta resolución o escribir sobre cualquier superficie es
lo que faltaba para romper la barrera de lo tradicional y forzarnos a crear aplicaciones que pre-
senten el contenido de formas antes impensadas.
06_Silverlight.qxp 9/30/09 1:34 PM Page 219
220

PREGUNTAS TEÓRICAS
1 ¿QuéformatosdeaudiosoportaSilverlight2?
2 ¿Mediante qué métodos podemos saber la
posición actual de reproducción de un soni-
do o música?
3 ¿Qué método es necesario ejecutar para
quitar el sonido por completo de una re-
producción en curso?
4 ¿Qué control necesitamos para reproducir
video en las aplicaciones Silverlight 2?
5 ¿Cuáles son los formatos de video que pue-
den ser manejados por Silverlight 2?
6 ¿A qué hace referencia la tecnología Deep
Zoom?
7 ¿Qué control XAML necesitamos utilizar pa-
ra incluir un elemento Deep Zoom dentro
de nuestra aplicación Silverlight 2?
8 ¿Cuál es el objetivo del archivo denominado
dzc_output.xml?
9 ¿Cómo se reconocen los trazos creados con
InkPresenter desde el código C#?
10¿Qué objeto define el tipo de trazo usado
por InkPresenter?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Intente reproducir sonidos desde una di-
rección web remota, haciendo uso del con-
trol MediaElement.
2 InkPresenter para Windows Presentation
Foundation posee la capacidad de recono-
cer la escritura y transformarla a letras.
Intente implementar esta característica.
3 Recolecte la información creada con Ink-
Presenter y almacénela en formato XML.
4 Con la información recolectada en el ejer-
cicio anterior, trate de volver a mostrarla
en la aplicación Silverlight 2.
5 Teniendo diferentes imágenes, intente
crear una presentación Deep Zoom. Con la
información que este componente retorna,
muestre información en una aplicación Sil-
verlight 2 basada en la imagen que el usua-
rio esté visualizando.
06_Silverlight.qxp 9/30/09 1:34 PM Page 220
Interconexión
Ampliar las funcionalidades 222
Silverlight desde C# 222
WebClient 230
Enviar información 233
Almacenamiento aislado 239
Implementar
el almacenamiento aislado 240
Capacidad de almacenamiento 245
Almacenar configuraciones 247
OpenFileDialog 251
Manejo de hilos 255
El concepto de hilos 256
Temporizador 257
Personalizar los hilos 259
Hilos y eventos 261
Consumir servicios desde
Silverlight 263
Crear un servicio WCF 270
Manipular datos 275
Enlazado de datos 276
LinQ 283
Resumen 287
Actividades 288
Capítulo 7
En el ambiente de Internet, aquello
que extiende las capacidades
de las aplicaciones es la facilidad
con la que se puede consumir
información de distintos medios,
incluso fuera de nuestro dominio.
Consultar la cotización de una moneda
o el clima son sólo una parte del todo
que puede ser construido, y Silverlight
no queda exento. Veamos el porqué.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
07_Silverlight.qxp 9/30/09 1:35 PM Page 221
AMPLIAR LAS FUNCIONALIDADES
Si bien en los capítulos vistos hasta ahora hemos hecho uso de C# para potenciar al-
gunas de las funcionalidades de Silverlight, debemos reconocer que la mayoría del tra-
bajo realizado recayó sobre el código XAML. Esto se debe a que mucha funcionalidad
puede ser creada desde el mismo código XAML, colocando sólo algunas gotas de C#
como soporte. De cualquier manera, lo que podríamos conseguir redunda en los as-
pectos visuales y no genera mayor interacción con el usuario que haga uso de nuestra
aplicación Silverlight. Sin embargo, con líneas de código de programación avanzadas,
en Silverlight podemos hacer mucho más, como conectarnos a servicios web para
consumir o enviar información, modificar la estructura del código XAML en tiempo
de ejecución o almacenar información en el equipo del usuario para utilizarla con pos-
terioridad. En este capítulo hablaremos de estas cualidades por medio de ejemplos va-
riados, donde extenderemos la aplicación Silverlight para que pase de ser un simple
visualizador de imágenes y videos, o un contenedor de animaciones, a algo mucho
más robusto y listo para ser usado en ámbitos empresariales o con fines tales como el
comercio electrónico o, por qué no, hasta la creación de juegos en la red.
SILVERLIGHT DESDE C#
Es posible que una de las áreas más atractivas del desarrollo de software sea la que se
refiere a la creación de juegos. En ésta se suelen aplicar muchas ciencias y técnicas
externas del software, como el uso de la física o la matemática. Al mismo tiempo, en
este tipo de desarrollo nos encontramos con acertijos lógicos que desafían nuestro
intelecto al tratar de optimizar al máximo el uso de recursos del equipo o para en-
contrar la mejor forma posible de mover elementos por la pantalla y simular anima-
ciones típicamente relacionadas con los juegos. Iniciemos, entonces, el uso intensivo
de C# para Silverlight con la creación de un juego. Este juego es bastante conocido y
consiste en armar una imagen desplazando cuadrados, que contienen parte de ella, a
un único espacio vacío del tablero de juego. Podremos mover sólo una parte a la vez,
tratando de formar la imagen previsualizada de manera completa. Primero, crearemos
en el código XAML una superficie de dibujado; para esto, necesitaremos de un con-
trol Canvas y un control Image donde visualizar la figura correctamente ensamblada.
UserControl x:Class=”Capitulo7ModificacionCanvas.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”810” Height=”300”
7. INTERCONEXIÓN
222
07_Silverlight.qxp 9/30/09 1:35 PM Page 222
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006”
mc:Ignorable=”d”
Grid x:Name=”LayoutRoot” Background=”White”
Canvas x:Name=”ContenedorJuego” /
Image Source=”Froblins4.png”
Height=”300” Width=”400” Stretch=”Fill”
HorizontalAlignment=”Right” d:LayoutOverrides=”HorizontalAlignment,
Width”/
TextBlock Visibility=”Collapsed” HorizontalAlignment=”Left”
VerticalAlignment=”Top” Text=”¡Has Ganado!” TextWrapping=”Wrap”
Margin=”109,132,0,0” FontSize=”20” Width=”144.658” FontWeight=”Bold”
FontFamily=”Interfaz de usuario portátil” x:Name=”textblockGanador”/
/Grid
/UserControl
En la Figura 1, vemos cómo se muestra la imagen y, también, podemos visualizar el
árbol de soluciones, donde notaremos que hemos agregado una imagen a él. Esta
imagen será usada como modelo guía, tanto para que el jugador pueda saber cuál
es el resultado final por ensamblar, como para que nuestro código tome esta ima-
gen y la desordene en pequeñas piezas para crear la esencia del juego.
Figura 1. Primera figura definida en el control Image.
El segundo paso consta de la creación del tablero de juego. Para esto, crearemos
código que cargue la imagen de manera dinámica desde una dirección web dada.
Silverlight desde C#
223
07_Silverlight.qxp 9/30/09 1:35 PM Page 223
public Page()
{
InitializeComponent();
CrearTablero();
}
Canvas[] vectorCanvas = new Canvas[16];
Image[] imagenes = new Image[16];
int[] tablero = new int[16];
private void CrearTablero()
{
Uri uri = new Uri(“Froblins4.png”, UriKind.Relative);
int n = 0;
for (int x = 0; x  4; x++)
for (int y = 0; y  4; y++)
{
n = (x * 4) + y;
imagenes[n] = new Image();
imagenes[n].Height = 400;
imagenes[n].Width = 400;
imagenes[n].Stretch = Stretch.UniformToFill;
RectangleGeometry r = new RectangleGeometry();
r.Rect = new Rect((x * 100), (y * 100), 100, 100);
imagenes[n].Clip = r;
imagenes[n].Source = new BitmapImage(uri);
imagenes[n].SetValue(Canvas.TopProperty, Convert.ToDouble(y *
100 * -1));
imagenes[n].SetValue(Canvas.LeftProperty, Convert.ToDouble(x *
100 * -1));
vectorCanvas[n] = new Canvas();
vectorCanvas[n].Width = 100;
vectorCanvas[n].Height = 100;
vectorCanvas[n].Children.Add(imagenes[n]);
vectorCanvas[n].SetValue(Canvas.NameProperty, “C” +
n.ToString());
vectorCanvas[n].MouseLeftButtonDown += new
MouseButtonEventHandler(Page_MouseLeftButtonDown);
if (n  15)
7. INTERCONEXIÓN
224
07_Silverlight.qxp 9/30/09 1:35 PM Page 224
this.ContenedorJuego.Children.Add(vectorCanvas[n]);
}
barajar();
dibujarTablero();
}
Notemos que, por medio del objeto Uri, hacemos referencia a la imagen que se va a
cargar, imagen que será usada para definir el tablero de juego. Luego, con dos bucles,
definimos las partes de la imagen, tanto horizontales como verticales. En el bucle
interno notamos que, usando la librería de clases de Microsoft .Net, en Silverlight po-
demos crear nuestras propias imágenes. En este caso, con la siguiente instrucción:
imagenes[n] = new Image();
Esta imagen es configurada con sus dimensiones y posición. Pero lo importante
es representado por el siguiente código:
RectangleGeometry r = new RectangleGeometry();
r.Rect = new Rect((x * 100), (y * 100), 100, 100);
imagenes[n].Clip = r;
En él, creamos un nuevo rectángulo de 100 pixeles de ancho por 100 pixeles de alto,
desplazándolo una cantidad en X y otra en Y sobre la imagen previamente cargada.
Pensemos en esta acción como si estuviéramos enfocando sólo parte de una imagen
más grande, en la cual desplazamos un rectángulo de visión por sobre una sola sec-
ción de 100 pixeles de ancho por 100 pixeles de alto. Acto seguido, asignamos este
rectángulo a la propiedad Clip de la imagen. Recordaremos esta propiedad vista en el
capítulo anterior, cuando trabajábamos con videos e InkPresenter. Esta propiedad li-
mitará el área de visión de la imagen sólo al rectángulo previamente creado. Al final
del método ya descrito, encontramos la llamada a dos métodos más, uno para mez-
clar o barajar las imágenes y otro para dibujar el tablero de juego en el estado actual.
private void barajar()
{
for (int i = 0; i  15; i++)
{
Silverlight desde C#
225
07_Silverlight.qxp 9/30/09 1:35 PM Page 225
tablero[i] = i;
}
Random randomizador = new Random(System.DateTime.Now.Second);
for (int i = 0; i  100; i++)
{
int numero1 = randomizador.Next(15);
int numero2 = randomizador.Next(15);
if (numero1 != numero2)
{
int temporal = tablero[numero1];
tablero[numero1] = tablero[numero2];
tablero[numero2] = temporal;
}
}
tablero[15] = -1;
}
private void dibujarTablero()
{
int x = 0;
int y = 0;
for (int i = 0; i  15; i++)
{
x = i / 4;
y = i % 4;
if (tablero[i] = 0)
{
vectorCanvas[tablero[i]].SetValue(Canvas.TopProperty,
Convert.ToDouble(y * 100));
vectorCanvas[tablero[i]].SetValue(Canvas.LeftProperty,
Convert.ToDouble(x * 100));
}
}
}
El método barajar() mezclará de forma aleatoria las imágenes, creando un nue-
vo tablero. Por otro lado, el método dibujarTablero() posicionará cada una de las
imágenes sobre la base base del tablero actual. El resultado de esto podemos ver-
lo en la Figura 2, que aparece en la próxima página.
7. INTERCONEXIÓN
226
07_Silverlight.qxp 9/30/09 1:35 PM Page 226
Figura 2. La imagen desarmada y lista para que iniciemos el juego.
El paso final es el de darle movimiento e interacción con el usuario. Así, cada vez que
el usuario presione una de las imágenes, ésta deberá ocupar el espacio en blanco conti-
guo, si lo hubiere, y dejar su espacio libre para que otra imagen pueda ocuparlo.
private void verificarGanador()
{
bool tableroCompleto = true;
for (int i = 0; i  15; i++)
{
if (i != tablero[i])
{
tableroCompleto = false;
break;
}
}
if (tableroCompleto)
{
//Tenemos un ganador!
this.textblockGanador.Visibility = Visibility.Visible;
}
}
private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Silverlight desde C#
227
07_Silverlight.qxp 9/30/09 1:35 PM Page 227
Canvas canvas = sender as Canvas;
int identificadorCanvas = -1;
int espacioTablero = -1;
int espacioVacio = -1;
for (int i = 0; i  16; i++)
{
if (canvas == vectorCanvas[i])
{
identificadorCanvas = i;
break;
}
}
for (int i = 0; i  16; i++)
{
if (tablero[i] == identificadorCanvas)
{
espacioTablero = i;
}
else if (tablero[i] == -1)
{
espacioVacio = i;
}
}
if ((espacioTablero == espacioVacio + 1) ||
(espacioTablero == espacioVacio - 1) ||
(espacioTablero == espacioVacio + 4) ||
(espacioTablero == espacioVacio - 4))
{
int x = espacioVacio / 4;
int y = espacioVacio % 4;
7. INTERCONEXIÓN
228
_`
Curiosamente, uno de los sitios más populares para la visualización de videos, YouTube, usó los
servicios de streaming de Silverlight para transmitir los eventos en vivo de March Madness. Es-
tos eventos pueden ser vistos en la siguiente dirección: www.youtube.com/marchmadness.
EL USO DE SILVERLIGHT EN LA WEB
07_Silverlight.qxp 9/30/09 1:35 PM Page 228
vectorCanvas[identificadorCanvas].SetValue(Canvas.TopProperty,
Convert.ToDouble(y * 100));
vectorCanvas[identificadorCanvas].SetValue(Canvas.LeftProperty,
Convert.ToDouble(x * 100));
tablero[espacioVacio] = identificadorCanvas;
tablero[espacioTablero] = -1;
verificarGanador();
}
}
Podemos notar que el evento donde se captura el presionado del mouse fue en-
lazado de manera manual en la inicialización de la aplicación Silverlight mediante
el código que vemos a continuación:
vectorCanvas[n].MouseLeftButtonDown += new
MouseButtonEventHandler(Page_MouseLeftButtonDown);
Debido a eso, esta acción será capturada por el método antes descrito; método
que podemos ver en la siguiente línea:
private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
...
...
En este método, se identifica qué objeto originó el evento de presionado del botón del
mouse, buscando en la lista de objetos Canvas cuál concuerda con el que ejecutó el
Silverlight desde C#
229
,
Sólo con agregar un poco más de funcionalidad al ejemplo planteado, podríamos tener un juego
aún más complejo. Pensemos en la posibilidad de adicionar una lista de imágenes de las que se-
leccionar, modificar la dificultad agregando más divisiones a la imagen, etcétera. Nuestro único
límite es la imaginación.
UN PASO MÁS ALLÁ
07_Silverlight.qxp 9/30/09 1:35 PM Page 229
evento. De esta forma, es posible acceder a sus propiedades, incluida su posición, y si
está contiguo a un espacio en blanco. Al cumplir esta última característica, la imagen
se moverá a ese lugar y se verificará si el tablero se ha formado de manera completa.
Figura 3. Nuestro tablero de juego una vez movidas algunas piezas.
WebClient
El objeto WebClient nos da la posibilidad de enviar y recibir información de for-
ma asíncrona desde y hacia cualquier destino conformado por una dirección URL
(Uniform Resource Locator o en castellano, localizador uniforme de recursos). Con
WebClient podríamos, por ejemplo, leer información de texto que se encuentre
en cualquier parte de una web, o conocer noticias en formato RSS (Really Simple
Syndication, o en castellano, distribución simple de contenido). De igual forma,
podríamos consumir cualquier otro tipo de información que nos retornara algu-
na forma de texto desde la Web. En el siguiente ejemplo, crearemos un lector
de noticias en formato RSS, haciendo uso del objeto WebClient y XLinQ para ma-
nipular las consultas sobre el contenido. Como primera instancia, crearemos los
controles XAML donde se mostrarán los resultados de la consulta.
UserControl xmlns:data=”clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”
x:Class=”Capitulo7WebClient.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400” Height=”300”
7. INTERCONEXIÓN
230
07_Silverlight.qxp 9/30/09 1:35 PM Page 230
Grid x:Name=”LayoutRoot” Background=”White”
data:DataGrid x:Name=”RssFeed”
AutoGenerateColumns=”True”/data:DataGrid
/Grid
/UserControl
En este ejemplo, usaremos un control DataGrid para mostrar la lista de registros
que obtengamos después de haber consultado la fuente RSS. El siguiente paso es
hacer uso del objeto WebClient para lanzar una petición asíncrona a la fuente RSS
y tomar el resultado por mostrar.
public Page()
{
InitializeComponent();
WebClient conectorWeb = new WebClient();
Uri direccionRSS = new Uri(“http://feeds2.feedburner.com/redusers”);
conectorWeb.Encoding = Encoding.UTF8;
conectorWeb.DownloadStringCompleted +=
new
DownloadStringCompletedEventHandler(conectorWeb_DownloadStringCompleted);
conectorWeb.DownloadStringAsync(direccionRSS);
}
Al comienzo, creamos un objeto WebClient que usaremos para conectarnos a la fuen-
te RSS. También es necesaria una instancia del objeto Uri. Este objeto representa
una dirección URL física y la utilizaremos para especificar el origen de la fuente de
datos de la que consumiremos la información. WebClient posee una serie de even-
tos que se dispararán sobre la base de las acciones que realicemos.
• DownloadProgressChanged: se disparará en el momento en el que una llamada asín-
crona de descarga de contenidos pueda transferir toda o parte de la información.
• DownloadStringCompleted: se ejecuta siempre que un elemento descargado de ma-
nera asíncrona se ha descargado por completo.
• OpenReadCompleted: ocurre cuando una acción de lectura de un recurso de ma-
nera asíncrona se ha completado.
• OpenWriteCompleted: se disparará cuando exista una operación de apertura de un
archivo para escribir en él y se haya completado esta acción.
• UploadProgressChanged: evento que marca cuando parte de una operación de en-
vío de información ha transferido todo o una porción de los datos.
Silverlight desde C#
231
07_Silverlight.qxp 9/30/09 1:35 PM Page 231
• UploadStringCompleted: ocurre cuando finaliza una acción de envío de información.
• WriteStreamClosed: en el momento en que una operación de escritura se ha com-
pletado, este evento se ejecutará.
De la lista anterior, usaremos el evento DownloadStringCompleted para que nos avise
cuándo la información se descargó por completo. Al ejecutar el código, podemos ver
cómo este evento trae la información desde la fuente.
Figura 4. En esta imagen, vemos el modo
de depuración, con los resultados desde la fuente RSS.
A continuación, colocaremos el siguiente código dentro del método del evento
DownloadStringCompleted.
private void conectorWeb_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
XDocument documentoXML = XDocument.Parse(e.Result.ToString());
var RSS = from fuentes in documentoXML.Descendants(“item”)
select new EntidadRSS
{
Titulo = (string)fuentes.Element(“title”),
Descripcion =
(string)fuentes.Element(“description”),
Link = (string)fuentes.Element(“link”)
};
7. INTERCONEXIÓN
232
07_Silverlight.qxp 9/30/09 1:35 PM Page 232
this.RssFeed.ItemsSource = RSS;
}
Una vez que la descarga del contenido es ejecutada, tomaremos este contenido desde
los argumentos del evento. El objeto e posee una propiedad llamada Result (resulta-
dos), donde se encontrará el contenido de la descarga. Este contenido es asignado a
un objeto del tipo XDocument, objeto que puede administrar XML para facilitar su
manipulación. Por último, mediante una consulta XLinQ, se toman los datos im-
portantes como título, descripción e hipervínculo de acceso a la noticia, alojando
todos los resultados dentro de una colección de objetos del tipo EntidadRSS. Ésta es
una entidad que creamos para este caso y que podemos ver a continuación.
public class EntidadRSS
{
public string Titulo { get; set; }
public string Descripcion { get; set; }
public string Link { get; set; }
}
Figura 5. Las fuentes RSS cargadas en la grilla.
Enviar información
Así como hemos podido obtener información desde una fuente de datos remota, es
posible enviar información hacia la fuente y esperar una respuesta basada en esto. Po-
demos hacer uso del mismo modelo antes planteado, pero adicionándole parámetros
Silverlight desde C#
233
07_Silverlight.qxp 9/30/09 1:35 PM Page 233
que se incluirán en el envío de la información. Esta información podrá ser maneja-
da por el destino, se analizará y, según ella, se generará una salida para visualizar en
la aplicación Silverlight. Como primer paso, crearemos una aplicación Silverlight que
incluya por defecto un sitio web de prueba (para recordar cómo hacerlo, podemos
ver otra vez el capítulo 3). Crearemos un nuevo sitio web junto con la aplicación
Silverlight para facilitarnos las pruebas de este ejemplo. Una vez creado el proyecto,
tendremos que ver una estructura similar a la planteada en la siguiente figura.
Figura 6. Aplicación Silverlight y sitio web en la misma solución de proyecto.
Utilizaremos el sitio web existente para que actúe como recolector de mensajes, el
que leerá la información enviada por la aplicación Silverlight y devolverá una res-
puesta para mostrar en ella. Implementaremos HttpHandler (manejadores web)
para que representen nuestros puntos de entrada de datos. Para lograr esto, dentro
del archivo Web.Config del sitio web, tendremos que agregar el manejador en cues-
tión. Junto con los manejadores creados por defecto, adicionaremos el nuestro.
httpHandlers
remove verb=”*” path=”*.asmx”/
add verb=”*” path=”capturaDeInformacion.aspx”
type=”Capitulo7Posting.Web.ManejadorHTTP, Capitulo7Posting.Web”/
add verb=”*” path=”*.asmx” validate=”false”
type=”System.Web.Script.Services.ScriptHandlerFactory,
System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35”/
add verb=”*” path=”*_AppService.axd” validate=”false”
7. INTERCONEXIÓN
234
07_Silverlight.qxp 9/30/09 1:35 PM Page 234
type=”System.Web.Script.Services.ScriptHandlerFactory,
System.Web.Extensions, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35”/
add verb=”GET,HEAD” path=”ScriptResource.axd”
type=”System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions,
Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35”
validate=”false”/
/httpHandlers
En el HttpHandler declarado, éste tomará todas las peticiones que se realicen dentro
de nuestro sitio web bajo el nombre de capturaDeInformacion.aspx. Todas las peticio-
nes que se realicen bajo este nombre serán redirigidas a la clase ManejadorHTTP, por lo
que deberemos adicionar esta clase y su código respectivo a nuestra aplicación web.
public class ManejadorHTTP
: IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = “text/xaml”;
context.Response.Write(“Canvas
xmlns=’http://schemas.microsoft.com/client/2007’ “ +
“xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’” +
Silverlight desde C#
235
RRR
Un HttpHandler nos otorga la posibilidad de capturar entradas HTTP a nuestro sitio web bajo un
nombre específico, sin tener que contar necesariamente con la página web física. Para poder
usar HttpHandler, es necesario especificar el nombre de la clase que manejará la petición, así
como el espacio de nombre que la contiene.
HTTPHANDLER
07_Silverlight.qxp 9/30/09 1:35 PM Page 235
“TextBlock Foreground=’black’ Padding=’10’ FontSize=’20’Hola
“ +
context.Request.QueryString[“Texto”] +
“/TextBlock/Canvas”);
}
}
Como vemos en el código anterior, la clase ManejadorHTTP implementa la interfaz
IHttpHandler, definiéndola como un manejador HTTP. Esta interfaz implementa
dos métodos, teniendo como importante el llamado ProcessRequest. Este método
presenta un comportamiento similar al de un evento y se disparará cada vez que se
haga una petición web que sea capturada por el manejador HTTP definido con
anterioridad. En el objeto context, podremos encontrar toda la información refe-
rente a la petición HTTP, incluso los valores enviados por el cliente. Al mismo
tiempo, todo resultado que escribamos dentro del objeto context será enviado de
vuelta al cliente, por lo que podremos crear cualquier tipo de contenido y enviar-
lo de manera directa a nuestra aplicación Silverlight.
Como vemos en las dos líneas de código de este método, la primera redefine el
tipo de salida, especificando que ésta será del tipo texto plano y con formato
XAML. La siguiente línea crea el texto de un control Canvas que contiene un
control TextBlock que muestra un mensaje. Este mensaje incluye una palabra,
más lo enviado por el usuario. De esta forma, terminamos de definir el punto de
contacto de nuestra aplicación Silverlight y un servicio o recolector de mensajes
distante. Del lado de Silverlight, lo primero que hacemos es crear el código
XAML para contener esta información y para darle la posibilidad al usuario de
enviarla. Veámoslo a continuación:
UserControl x:Class=”Capitulo7Posting.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400” Height=”300”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006”
mc:Ignorable=”d”
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition Height=”0.16*”/
RowDefinition Height=”0.84*”/
/Grid.RowDefinitions
7. INTERCONEXIÓN
236
07_Silverlight.qxp 9/30/09 1:35 PM Page 236
Grid.ColumnDefinitions
ColumnDefinition/
/Grid.ColumnDefinitions
TextBox Margin=”57,8,0,18” Text=”” TextWrapping=”Wrap” Width=”143”
HorizontalAlignment=”Left” x:Name=”textBox”/
Button Click=”Button_Click” HorizontalAlignment=”Right”
Margin=”0,8,153,18” Content=”Enviar” d:LayoutOverrides=”Width,
Height”/
TextBlock HorizontalAlignment=”Left” Margin=”8,14,0,18”
Text=”Mensaje:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
StackPanel x:Name=”contenedor” Margin=”8,8,8,8” Grid.Row=”1”/
/Grid
/UserControl
Figura 7. Aplicación Silverlight que consumirá un elemento distante.
Si bien ya hemos visto este código en diferentes ocasiones, debemos destacar la pre-
sencia del control StackPanel al final del código XAML. En este control, aplicaremos
la respuesta del elemento HttpHandler ya creado. Por último, creamos el código que
manejará la petición y creará el control Silverlight basado en su código XAML.
private void Button_Click(object sender, RoutedEventArgs e)
{
WebClient conectorWeb = new WebClient();
Silverlight desde C#
237
07_Silverlight.qxp 9/30/09 1:35 PM Page 237
Uri direccionRSS = new
Uri(“http://localhost:1870/capturaDeInformacion.aspx?Texto=” +
this.textBox.Text);
conectorWeb.Encoding = Encoding.UTF8;
conectorWeb.DownloadStringCompleted +=
new
DownloadStringCompletedEventHandler(conectorWeb_DownloadStringCompleted);
conectorWeb.DownloadStringAsync(direccionRSS);
}
void conectorWeb_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
Canvas control = XamlReader.Load(e.Result.ToString()) as Canvas;
this.contenedor.Children.Add(control);
}
En el código anterior, vemos cómo el valor de la caja de texto es pasada en la ruta
de navegación creada por el objeto Uri.
Uri direccionRSS = new
Uri(“http://localhost:1870/capturaDeInformacion.aspx?Texto=” +
this.textBox.Text);
Esto garantizará que el HttpHandler pueda leer el valor introducido por el usua-
rio y actuar en consecuencia. En el código, aparece un nuevo objeto que todavía
no habíamos visto. Este objeto XamlReader permite crear controles Silverlight a
partir del texto representativo en XAML. Este control carga el texto devuelto por
el HttpHandler y crea una nueva instancia del control en cuestión. Finalmente, adi-
cionamos este resultado a la lista de controles hijo del StackPanel.
7. INTERCONEXIÓN
238
RRR
Cuando usamos las entradas del usuario como parámetros en nuestras aplicaciones, debere-
mos tener sumo cuidado. Las entradas de los usuarios siempre deben ser comprobadas para
que no contengan caracteres o código ejecutable que pueda generar comportamientos no dese-
ados. Cross Site Scripting o SQL Injection son dos de las vulnerabilidades más comunes.
SEGURIDAD SOBRE PARÁMETROS
07_Silverlight.qxp 9/30/09 1:35 PM Page 238
Figura 8. El resultado devuelto por el HttpHandler
y el nuevo control creado incluido dentro del StackPanel.
Como hemos podido comprobar, Silverlight puede salir fuera de su contenedor para
comunicarse con otras aplicaciones conectadas a la red. Si bien sólo hemos consumi-
do información de páginas web, es posible hacerlo de servicios web, así como de la
nueva plataforma de comunicación de Microsoft, WCF (Windows Communication
Foundation). Veremos estas alternativas, más adelante, en este mismo capítulo.
ALMACENAMIENTO AISLADO
Silverlight posee un mecanismo para poder guardar información de manera local en
el cliente que esté ejecutando la aplicación. Si tenemos experiencia en el desarrollo
web, podríamos asociar la idea de este almacenamiento al utilizado por las cookies,
elementos que son almacenados y administrados por el navegador del cliente, usados
por lo general para dejar alguna información en ese equipo y que serán consultadas
en posteriores ocasiones. Pero si bien conceptualmente resulta algo similar, el alma-
cenamiento aislado en Silverlight presenta otras características. Pensemos en esta
funcionalidad como en la posibilidad de tener una parte del disco duro de la má-
quina cliente para almacenar de manera segura información desde nuestra aplicación
Silverlight. Podríamos, por ejemplo, cargar archivos desde el cliente, almacenarlos en
este espacio reservado y usarlos luego en nuestra aplicación. De esta manera, le aho-
rramos al usuario el tiempo de carga y evitamos pedirle que haga el mismo trabajo
todas las veces que use la aplicación. Por otro lado, esta característica trae consigo un
concepto de seguridad. Tengamos en cuenta que los navegadores web restringen el
Almacenamiento aislado
239
07_Silverlight.qxp 9/30/09 1:35 PM Page 239
acceso a archivos en el equipo del usuario. De esta forma, se aseguran de que dife-
rentes aplicaciones y sitios web no puedan causar daño alguno al sistema operativo del
usuario. Debido a este impedimento, y para no romper esta condición, Silverlight nos
permite crear y leer información desde el equipo del usuario de manera contenida, sin
poder acceder más allá del espacio reservado para la aplicación.
Implementar el almacenamiento aislado
Para poder usar almacenamiento aislado es necesario incluir el espacio de nombres
System.IO.IsolatedStorage en nuestro código. Una vez que lo hemos adicionado, po-
dremos acceder de manera más fácil a los objetos que administran esta funcionalidad.
Debido a que Silverlight es el que nos proveerá y administrará el espacio reservado pa-
ra nuestra aplicación, deberemos recuperar este espacio antes de poder leer o escribir
cualquier información en él. Este espacio de nombre tiene tres elementos básicos:
• IsolatedStorageFile: representa el almacén donde se encuentran todos los archivos
correspondientes a la aplicación y al usuario. Incluye archivos y directorios.
• IsolatedStorageFileStream: es utilizado para leer o escribir los distintos archivos
dentro del almacén de datos.
• IsolatedStorageSettings: es un diccionario de datos representado por un par llave/
valor, que va a ser almacenado en el almacén de datos.
Obtener el espacio designado para nuestra aplicación es simple. Podemos hacerlo
de la manera que vemos a continuación:
IsolatedStorageFile almacen =
IsolatedStorageFile.GetUserStoreForApplication();
Esto retornará una referencia al directorio y al espacio designado para nuestra apli-
cación. Una vez que tenemos esta referencia, todo lo que leamos o escribamos pasa-
rá por este espacio reservado. Si tenemos experiencia en el manejo de archivos bajo
Microsoft .Net, notaremos que el manejo del espacio reservado en Silverlight posee
algunos puntos de contacto con su superior, teniendo diferentes métodos para cre-
ar, borrar y leer archivos, así como para crear o borrar directorios. Los siguientes son
los métodos que tenemos a nuestra disposición para trabajar con el almacén aislado:
• CreateDirectory: crea un nuevo directorio dentro del almacén. Podremos espe-
cificar un nombre para el directorio.
• DeleteDirectory: borra un directorio del almacén.
• CreateFile: crea un nuevo archivo, retornando un objeto IsolatedStorageFileStream.
7. INTERCONEXIÓN
240
07_Silverlight.qxp 9/30/09 1:35 PM Page 240
• DeleteFile: elimina un archivo del almacén.
• Remove: se encarga de eliminar por completo el almacén junto con todos sus
directorios y archivos contenidos.
• OpenFile: este método abre un archivo guardado en el almacén y retorna un ob-
jeto IsolatedStorageFileStream.
• FileExists: verifica la existencia de un archivo en particular. Es útil en casos en los
que necesitemos saber si un archivo determinado ya fue creado o no.
• DirectoryExists: verifica la existencia de un directorio en particular.
• GetFileNames: devuelve un vector con los nombres de los archivos existentes en el
almacén o en un directorio específico de éste.
• GetDirectoryNames: este método retorna un vector que contiene los nombres de
los directorios dentro del almacén.
Para poder crear un nuevo archivo dentro del almacén, escribiremos lo siguiente:
IsolatedStorageFile almacen;
public Page()
{
InitializeComponent();
almacen = IsolatedStorageFile.GetUserStoreForApplication();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
using (IsolatedStorageFileStream archivo
= almacen.CreateFile(“archivo.txt”))
{
StreamWriter streamWriter = new StreamWriter(archivo);
streamWriter.Write(DateTime.Now);
streamWriter.Close();
}
this.mensaje.Text = “Se escribió un archivo.”;
}
Como vemos, para este caso se inicializa el almacén y el evento que disparará el bo-
tón. Usaremos este almacén para crear un archivo llamado archivo.txt, escribiendo
en él la fecha actual. En la Figura 9, ubicada en la página siguiente, podemos ob-
servar el resultado obtenido con lo que hemos realizado.
Almacenamiento aislado
241
07_Silverlight.qxp 9/30/09 1:35 PM Page 241
Figura 9. El archivo fue creado con éxito y se envía
un mensaje al usuario para informarlo de este hecho.
Así como hemos podido crear un nuevo archivo y guardar información en él,
también tenemos la posibilidad de recuperar esa información y manipularla. Po-
dremos hacer esto con el siguiente código:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
string contenido = string.Empty;
using (IsolatedStorageFileStream archivo
= almacen.OpenFile(“archivo.txt”,FileMode.OpenOrCreate))
{
StreamReader streamReader = new StreamReader(archivo);
contenido = streamReader.ReadToEnd();
streamReader.Close();
7. INTERCONEXIÓN
242
,
Es importante usar el método Close() después de cada operación con archivos para marcar el fin
de su uso y así liberarlo. Si no lo hiciéramos, el archivo podría quedar tomado por la aplicación y,
al tratar de accederlo nuevamente, obtendríamos un error ya que el archivo está en uso.
CIERRE DE ARCHIVOS
07_Silverlight.qxp 9/30/09 1:35 PM Page 242
}
this.mensaje.Text = “Un archivo leído. Contenido: “ + contenido;
}
En este caso, el contenido del archivo es recuperado y almacenado en una variable tem-
poral para luego mostrar su valor en un mensaje, como vemos en la siguiente figura.
Figura 10. El archivo fue leído y su contenido mostrado.
Notemos que, una vez que abrimos el archivo para leerlo, podemos especificar
su modo de apertura mediante la enumeración FileMode. Esta enumeración po-
see algunas características especiales:
• CreateNew: especifica que se creará un nuevo archivo si no existiera anteriormente.
• Create: especifica que se creará un nuevo archivo. Si el archivo ya existe, entonces
éste será sobrescrito, y se perderán los datos del anterior.
• Open: abrirá un archivo existente. Si el archivo no existe, será arrojado un error.
• OpenOrCreate: abrirá o creará un archivo basado en su existencia. Si el archivo exis-
te, lo abrirá. Si no, creará uno nuevo.
• Append: abre un archivo existente. Al hacerlo, desplazará el punto de lectura hacia
el fin del archivo. De esta forma, lo que escribamos en él se hará al final, y adicio-
nará elementos al archivo existente.
Ya hemos creado y leído el archivo. Pero como dijimos, es posible hacer con él
todas las operaciones básicas con archivos. En este caso, borraremos el archivo
escribiendo el código que aparece en la próxima página:
Almacenamiento aislado
243
07_Silverlight.qxp 9/30/09 1:35 PM Page 243
private void Button_Click_2(object sender, RoutedEventArgs e)
{
almacen.DeleteFile(“archivo.txt”);
this.mensaje.Text = “Se eliminó el archivo.”;
}
Figura 11. El archivo fue eliminado del almacén.
Todos los archivos son almacenados en una ubicación específica dentro del sistema ope-
rativo. En este caso, se ubican en las carpetas que contienen información del usuario.
Figura 12. Ubicación del archivo creado en el almacén.
7. INTERCONEXIÓN
244
07_Silverlight.qxp 9/30/09 1:35 PM Page 244
Capacidad de almacenamiento
Por defecto, el espacio disponible para el almacenaje de datos es de 1 megabyte.
Por supuesto, es posible que en determinadas circunstancias necesitemos más es-
pacio. Debido a que, como comentamos antes, Silverlight respeta el modelo de
seguridad propuesto para el desarrollo web, no podremos aumentar la cantidad
de espacio sin la autorización previa por parte del usuario. Pensemos que, de po-
der pasar por alto este tipo de validaciones, estaríamos en condiciones de vulne-
rar la seguridad del usuario. Imaginemos que colmamos el total del espacio del
disco duro del cliente sin que éste se entere.
Definitivamente sería un problema y, por tal motivo, el usuario debe estar al tan-
to de esa acción antes de que nosotros podamos utilizar más del espacio que es
provisto por defecto. Es posible verificar e incrementar la cantidad de espacio
disponible escribiendo el siguiente código:
private void Button_Click_3(object sender, RoutedEventArgs e)
{
if (almacen.AvailableFreeSpace  2000 * 1024)
{
if (almacen.IncreaseQuotaTo(
almacen.Quota + (2000 * 1024) - almacen.AvailableFreeSpace))
{
this.mensaje.Text = “El espacio disponible es ahora de “ +
(almacen.Quota + (2000 * 1024)).ToString() + “ más.”;
}
else
{
this.mensaje.Text = “Usted no aceptó el incremento de
tamaño.”;
}
}
}
Almacenamiento aislado
245
RRR
Es necesario verificar el tamaño del almacén antes de hacer la petición de incremento. Si la cuo-
ta actual fuera del mismo tamaño o superior a la que estamos pidiendo, obtendrímos un error
con la advertencia de que la cuota existente es igual o superior a la que reclamamos.
TAMAÑO DEL ALMACÉN
07_Silverlight.qxp 9/30/09 1:35 PM Page 245
El código anterior intentará pedir 2 megabytes adicionales a los ya usados. Si bien
aún no hemos usado nada del primer megabyte del espacio por defecto, este código
intentará incrementar en 2 megabytes ese espacio. Al ejecutar el código, podemos ver
la ventana emergente que nos pide autorización para incrementar el espacio dispo-
nible, como se muestra en la figura siguiente.
Figura 13. Petición para incremento de la cuota en el almacén.
Si necesitamos conocer cuánto espacio utiliza la aplicación Silverlight, es posible ac-
ceder a esta información presionando el botón derecho del mouse y seleccionando
la opción Silverlight en el menú desplegable. Al hacerlo, veremos todas las propie-
dades de la aplicación en ejecución. En la última pestaña, aparecerán las propieda-
des relacionadas con el almacenamiento aislado, donde es posible saber el espacio
consumido actualmente y hasta cuánto podría crecer, además de poder liberar este
espacio con las opciones de esta ventana.
Figura 14. Opciones de la aplicación Silverlight donde
es posible ver el espacio de almacenamiento consumido y el disponible.
7. INTERCONEXIÓN
246
07_Silverlight.qxp 9/30/09 1:35 PM Page 246
Almacenar configuraciones
Es posible que necesitemos almacenar valores como textos u objetos complejos, pe-
ro sin la necesidad de tener que crear un archivo por nuestra cuenta. Podríamos,
por ejemplo, guardar la lista de productos de un carrito de compras o el nombre del
usuario que está usando la aplicación, pero sin llegar a tener que generar código para
manipular archivos almacenados de forma física. La característica de almacena-
miento aislado nos permite, además de la manipulación de archivos, la posibilidad
de almacenar tipos de datos de manera simple y rápida, que se pueda recuperar en
cualquier momento de la misma forma en la que fueron almacenados. Esto quiere
decir que, si guardáramos un objeto personalizado, recuperaríamos el mismo obje-
to. Crearemos dos botones y una caja de texto para permitir al usuario introducir
texto, que luego guardaremos y recuperaremos utilizando este mecanismo.
TextBox VerticalAlignment=”Bottom” Text=”” TextWrapping=”Wrap”
Margin=”121,0,117,72” Height=”25” x:Name=”aplicacion”/
TextBlock HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Text=”Valor
de aplicación:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”
Margin=”8,0,0,76”/
Button Click=”Button_Click_4” HorizontalAlignment=”Left”
VerticalAlignment=”Bottom” Content=”Almacenar”
d:LayoutOverrides=”Width” Margin=”8,0,0,29”/
Button Click=”Button_Click_5” HorizontalAlignment=”Left”
VerticalAlignment=”Bottom” Content=”Recuperar” Margin=”76,0,0,29”/
Como siguiente paso, tomaremos el valor de la caja de texto y la asignaremos a una
variable de configuración dentro del almacén.
private void Button_Click_4(object sender, RoutedEventArgs e)
{
IsolatedStorageSettings.ApplicationSettings[“Texto”] =
Almacenamiento aislado
247
RRR
El almacenamiento aislado tiene un comportamiento diferente al de las cookies. Éste no se ma-
neja por navegador, sino por usuario. Esto quiere decir que acceder a la misma aplicación con
diferentes navegadores utilizará el mismo espacio reservado, sin importar quién creó inicial-
mente este espacio de almacenamiento.
EL ALCANCE DEL ALMACENAMIENTO AISLADO
07_Silverlight.qxp 9/30/09 1:35 PM Page 247
this.aplicacion.Text;
this.aplicacion.Text = “”;
}
Esta variable no necesita existir previamente y será creada en el momento en el que
sea asignada por primera vez. Si la variable ya existiera, su contenido será rempla-
zado con el nuevo valor. En el ejemplo anterior, el nombre de la variable es Texto y
contendrá el valor introducido por el usuario. A continuación, podremos recuperar
este valor con el siguiente código:
private void Button_Click_5(object sender, RoutedEventArgs e)
{
this.aplicacion.Text =
IsolatedStorageSettings.ApplicationSettings[“Texto”].ToString();
}
ApplicationSettings retornará un tipo de datos Object, por lo que es necesario trans-
formarlo al tipo conocido, en este caso un String, para poder reasignarlo a la caja de
texto. Como podemos ver en la figura que aparece debajo, los resultados almace-
nados desde un navegador son visibles en el otro.
Figura 15. La variable almacenada por el usuario en el navegador
de la izquierda, es leída desde la aplicación Silverlight en el navegador de la derecha.
Como dijimos, es posible almacenar cualquier objeto o lista de éstos dentro de es-
tas variables de configuración. De cualquier manera, es necesario que tengamos en
cuenta que sólo podrán ser almacenados aquellos elementos que contengan la cua-
lidad de ser serializados. Esto quiere decir que podremos almacenar elementos,
7. INTERCONEXIÓN
248
07_Silverlight.qxp 9/30/09 1:35 PM Page 248
cuyos tipos de datos puedan ser transformados a XML. Para ilustrar esta posibili-
dad, crearemos una colección de entidades, alojándolas primero en una variable de
configuración que luego recuperaremos para llenar un control DataGrid.
UserControl xmlns:data=”clr-
namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”
x:Class=”Capitulo7AlmacenamientoObjetos.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400” Height=”300”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006”
mc:Ignorable=”d”
Grid x:Name=”LayoutRoot” Background=”White”
Button HorizontalAlignment=”Left” Margin=”8,8,0,0”
VerticalAlignment=”Top” Content=”Cargar lista”/
Button HorizontalAlignment=”Left” Margin=”82,8,0,0”
VerticalAlignment=”Top” Content=”Mostrar lista”
d:LayoutOverrides=”HorizontalAlignment”/
data:DataGrid Margin=”0,51,0,0”
x:Name=”grillaDeDatos”/data:DataGrid
/Grid
/UserControl
El siguiente paso es crear una clase que contenga nuestra entidad y sirva para alma-
cenar datos (podemos ver un ejemplo de esto en los capítulos 3 y 4). En el momento
en el que se ejecute el evento Click del botón, cargaremos una lista de nuestras
entidades y las almacenaremos en una variable de configuración.
private void Button_Click(object sender, RoutedEventArgs e)
{
ListProductos productos = new ListProductos();
productos.Add(new Productos()
{
Producto = “Producto 1”,
Cantidad = 10,
Categoria = “Categoria 1”,
Precio = 100
});
Almacenamiento aislado
249
07_Silverlight.qxp 9/30/09 1:35 PM Page 249
productos.Add(new Productos()
{
Producto = “Producto 2”,
Cantidad = 20,
Categoria = “Categoria 1”,
Precio = 50
});
//Agregar tantas como sean necesarias.
IsolatedStorageSettings.ApplicationSettings[“ListaProductos”] =
productos;
}
Como podemos ver, se agrega la lista de productos sin realizarle ninguna modi-
ficación. Esto se debe a que todos los elementos internos de la entidad pueden
ser transformados a XML sin problema alguno. Finalmente, en el evento del se-
gundo botón, leemos estos valores y los asignamos al control DataGrid. Para eso,
el código es el que aparece a continuación:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
this.grillaDeDatos.ItemsSource =
IsolatedStorageSettings.ApplicationSettings[“ListaProductos”] as
ListProductos;
}
Notemos que utilizamos la palabra reservada AS para transformar el resultado de la
variable de configuración al tipo conocido, o sea, una lista genérica de nuestra en-
tidad. El resultado de estas dos acciones las podemos ver en la Figura 16.
7. INTERCONEXIÓN
250
RRR
Serializar información no es una tarea trivial. Podemos encontrarnos atascados fácilmente al
momento de querer transformar nuestros objetos en distintos formatos de almacenamiento.
Al aplicar este mecanismo, también podremos realizar acciones con la información. En
http://msdn.microsoft.com/es-es encontraremos más información.
SERIALIZACIÓN
07_Silverlight.qxp 9/30/09 1:35 PM Page 250
Figura 16. DataGrid cargado con datos tomados desde una variable de configuración.
OpenFileDialog
OpenFileDialog es un control homónimo del usado en aplicaciones de escritorio. Per-
mite abrir una ventana donde el usuario deberá seleccionar un archivo de su equipo,
archivo que podremos leer y manipular. Encontramos este tipo de comportamiento en
páginas web en las que podemos seleccionar un archivo, como fotografías, para alojar-
las en un servidor. El código para crear un objeto del tipo OpenFileDialog es:
OpenFileDialog ventanaDialogo =
new OpenFileDialog();
Para abrir la ventana de selección, deberemos llamar al método ShowDialog(). Este
método retornará el valor True cuando el usuario aplique los archivos seleccionados.
OpenFileDialog ventanaDialogo = new OpenFileDialog();
ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt”;
ventanaDialogo.Multiselect = true;
if (ventanaDialogo.ShowDialog() == true)
{
...
En el código anterior, también podemos notar que es posible definir el filtro de
los archivos por buscar, así como si se permitirá seleccionar más de un archivo al
Almacenamiento aislado
251
07_Silverlight.qxp 9/30/09 1:35 PM Page 251
mismo tiempo. El ejemplo que vemos a continuación muestra todos los archivos
cargados por el usuario en un control ListBox.
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ventanaDialogo = new OpenFileDialog();
ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt”;
ventanaDialogo.Multiselect = true;
if (ventanaDialogo.ShowDialog() == true)
{
Liststring listaArchivos = new Liststring();
foreach (FileInfo archivo in ventanaDialogo.Files)
{
listaArchivos.Add(archivo.Name);
}
this.listaDeArchivos.ItemsSource = listaArchivos;
}
}
Figura 17. El filtro mostrará sólo archivos
con extensión TXT o de texto para seleccionar.
Luego de que el usuario selecciona los archivos permitidos por el filtro establecido,
todos sus nombres son listados en el control ListBox, como podemos observar en la
Figura 18, ubicada en la página siguiente.
7. INTERCONEXIÓN
252
07_Silverlight.qxp 9/30/09 1:35 PM Page 252
Figura 18. Lista de todos los archivos seleccionados por el usuario.
Podremos agregar tantos filtros como creamos necesarios. Para lograr esto, modifi-
caremos el filtro inicial incluyendo otros, de la siguiente manera:
ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt|Imágenes JPG
(*.jpg)|*.jpg”;
Ahora, tenemos un nuevo tipo disponible para seleccionar en el cuadro de diálogo:
Figura 19. Un nuevo filtro agregado
a la lista de elementos seleccionables.
Almacenamiento aislado
253
07_Silverlight.qxp 9/30/09 1:35 PM Page 253
Es posible combinar el uso del objeto OpenFileDialog con la funcionalidad de alma-
cenamiento aislado. En el siguiente ejemplo, copiaremos los archivos seleccionados
por el usuario a una sección del almacén reservado para nuestra aplicación.
IsolatedStorageFile almacen;
public Page()
{
InitializeComponent();
almacen = IsolatedStorageFile.GetUserStoreForApplication();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog ventanaDialogo = new OpenFileDialog();
ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt|Imágenes JPG
(*.jpg)|*.jpg”;
ventanaDialogo.Multiselect = true;
if (ventanaDialogo.ShowDialog() == true)
{
Liststring listaArchivos = new Liststring();
foreach (FileInfo archivo in ventanaDialogo.Files)
{
listaArchivos.Add(archivo.Name);
using (Stream datosArchivo = archivo.OpenRead())
{
using (IsolatedStorageFileStream datosAlmacen =
almacen.CreateFile(archivo.Name))
{
byte[] buffer = new byte[1024];
int count = 0;
do
{
count = datosArchivo.Read(buffer, 0,
buffer.Length);
if (count  0)
datosAlmacen.Write(buffer, 0, count);
} while (count  0);
}
7. INTERCONEXIÓN
254
07_Silverlight.qxp 9/30/09 1:35 PM Page 254
}
}
this.listaDeArchivos.ItemsSource = listaArchivos;
}
}
Por cada elemento leído desde el diálogo de archivos, crearemos un nuevo
archivo en el almacén con el mismo nombre, copiando sus datos de forma bina-
ria. Como resultado, podremos ver que los archivos seleccionados previamente
fueron copiados a la ruta del almacén.
MANEJO DE HILOS
Quizás, no estemos familiarizados con el manejo de hilos, también llamados threads
por su nombre en inglés. Esta característica es típica de las aplicaciones de escrito-
rio, donde es posible ejecutar más de un proceso, función o pieza de código de ma-
nera simultánea. Esto quiere decir que podremos tener más de una pieza funcional de
código dentro de nuestra aplicación, procesando información de manera paralela.
Para entender esto aún más, pensemos en código que podría tomar mucho tiempo
en ejecutarse, como modificar una imagen, insertar registros en una base de datos
de forma masiva o generar un cálculo matemático de alta complejidad. Estos pro-
cesos pueden tomar mucho tiempo en llevarse a cabo, y hacer esperar al usuario
hasta que ese proceso finalice antes de que pueda seguir usando nuestra aplica-
ción, podría resultar poco práctico. De esta forma, estos procesos de alta com-
plejidad podrían ser ejecutados de manera paralela haciendo que, en el momento
en el que terminen su ejecución, nos avisen para que podamos continuar con otro
tipo de tarea. Silverlight no está exento de esta capacidad, a pesar de tener una fir-
ma muy pequeña y estar pensado para que sea liviano y rápido.
Manejo de hilos
255
RRR
Si bien el uso de hilos puede ser de gran ayuda para la ejecución de tareas en paralelo, de-
bemos tener en cuenta que éste no es un recurso inagotable y, por más hilos que creemos y
tareas que ejecutemos en paralelo, el rendimiento de nuestra aplicación no será constante.
Es importante no abusar de estos elementos en nuestro código.
HILOS
07_Silverlight.qxp 9/30/09 1:35 PM Page 255
El concepto de hilos
En los diferentes capítulos ya hemos tenido algunos contactos con el manejo de hi-
los. Si bien no hemos creado ni declarado hilos de manera explícita, sí hemos usado
objetos que poseen un comportamiento similar. Objetos como Storyboard o Timer
son algunos ejemplos de componentes que pueden ejecutar código en un hilo de eje-
cución distinto del primario definido por la aplicación, disparando eventos basados
en ciertos estímulos ya configurados. Esto es posible debido a que el sistema opera-
tivo es el que administra los procesos de cada aplicación que se ejecuta, asignándole
un espacio de tiempo para realizar sus tareas. Así, el sistema operativo irá iterando
entre cada uno de estos procesos, además de sus propios procesos, y de esta forma
permitirá que las aplicaciones no tomen el control absoluto de todo el equipo.
Es común que el manejo de hilos pase desapercibido cuando usamos o desarrolla-
mos cualquier aplicación, pero pensemos que el hecho de que podamos mover el
puntero del mouse y al, mismo tiempo, escuchar música o escribir un documento
es gracias a que el sistema operativo, a altísima velocidad, está otorgándole una frac-
ción de tiempo a cada una de estas aplicaciones para que puedan realizar sus traba-
jos. En el caso de las aplicaciones visuales, todo el manejo de la interfaz visual, así
como de la lógica de esa aplicación, se realiza en un único hilo de ejecución. Debi-
do a esto, tener una tarea que capte todo el tiempo disponible otorgado por el sis-
tema operativo para la ejecución de procesos podría bloquear la interfaz visual,
haciendo pensar que la aplicación ha sufrido un problema y que no funcionará
correctamente. Para ilustrar esto, veamos el siguiente código:
public Page()
{
InitializeComponent();
ProcesoLargo();
}
public void ProcesoLargo()
{
for (long i = long.MinValue; i = long.MaxValue; i++)
{
}
}
El código anterior no es muy complejo, pero el bucle presentado itera entre valores
bastante amplios bloqueando por completo el hilo principal de ejecución de la apli-
cación, lo que hace que no podamos interactuar con ella hasta que el bucle finalice
7. INTERCONEXIÓN
256
07_Silverlight.qxp 9/30/09 1:35 PM Page 256
por completo. Como resultado de la ejecución del código anterior, somos proclives
a obtener errores como el que vemos en la siguiente figura.
Figura 20. La única alternativa posible
es terminar abruptamente la ejecución de la aplicación.
Para este tipo de tareas, entonces, lo recomendable sería crear un nuevo hilo de
ejecución para que estas líneas de código se ejecuten en paralelo y así no bloquear
toda la aplicación. Conozcamos algunas formas de hacerlo.
Temporizador
Una de las primeras implementaciones provistas por Microsoft .Net Framework
que implementan hilos son los temporizadores, también conocidos como Timers
por su nombre en inglés. En el caso de Silverlight, tenemos un temporizador
especial dentro del espacio de nombres System.Windows.Threading. Este tempori-
zador es llamado DispatcherTimer y cumple la función de disparar un evento basa-
do en un intervalo dado. DispatcherTimer posee las siguientes propiedades:
• Interval: el intervalo representa el tiempo en milisegundos que deberá transcurrir
antes de disparar el evento Tick.
• Start: inicia el temporizador. Una vez configurado el objeto DispatcherTimer, de-
bemos llamar al método Start() para iniciar la ejecución del temporizador.
• Stop: detiene la ejecución del temporizador.
• Tick: éste es el evento al que deberemos subscribirnos para recibir las alertas
disparadas por DispatcherTimer cada vez que transcurra el tiempo configurado
en la propiedad Interval que vimos al principio de esta lista.
Manejo de hilos
257
07_Silverlight.qxp 9/30/09 1:35 PM Page 257
Podríamos usar DispatcherTimer para generar una aplicación tipo reloj, actualizando
los minutos o segundos en tiempo real; o en otras implementaciones tales como el
envío de información hacia un servicio o página web desde nuestra aplicación
Silverlight sin intervención del usuario y, al mismo tiempo, sin bloquear el hilo
principal de ejecución de la aplicación. En el siguiente ejemplo, vemos cómo apli-
car este temporizador para actualizar el progreso de un control ProgressBar.
UserControl x:Class=”Capitulo7Hilos.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”
ProgressBar x:Name=”progressBar” VerticalAlignment=”Top”
Height=”24” Margin=”23,39,26,0” /
/Grid
/UserControl
Una vez que hemos definido el control ProgressBar, declaramos el temporizador
DispatcherTimer y actualizamos el resto del control ProgressBar por cada Tick()
ejecutado por el objeto temporizador.
DispatcherTimer temporizador;
public Page()
{
InitializeComponent();
temporizador = new DispatcherTimer();
temporizador.Tick += new EventHandler(temporizador_Tick);
temporizador.Interval = TimeSpan.FromSeconds(1);
temporizador.Start();
}
void temporizador_Tick(object sender, EventArgs e)
{
this.progressBar.Value++;
}
Como vemos en la Figura 21 de la próxima página, el control ProgressBar es ac-
tualizado dentro del rango de tiempo fijado por el control DispatcherTimer.
7. INTERCONEXIÓN
258
07_Silverlight.qxp 9/30/09 1:35 PM Page 258
Manejo de hilos
259
Figura 21. En cada navegador, vemos los diferentes estados
del control ProgressBar, actualizado cada un segundo de ejecución.
Personalizar los hilos
En el caso anterior, donde vimos el objeto DispatcherTimer, éste fue creado para reali-
zar una tarea específica: generar su propio proceso o hilo de ejecución y avisarnos cada
vez que el tiempo configurado fuera alcanzado. Este comportamiento no nos resultará
para nada práctico en casos más específicos o avanzados. Supongamos que necesitamos
modificar el comportamiento del control ProgressBar sobre la base del progreso real de
una tarea que es ejecutada por una función creada por nosotros. Para estos casos, es po-
sible colocar la ejecución de esa función o método en un hilo separado. Esto, como ya
dijimos, hará que el hilo principal, aquel que administra la interfaz del usuario, no se
bloquee, dándole al usuario una experiencia más agradable al ejecutar la aplicación.
private void RealizarProceso()
{
for (int i = 0; i  100; i++)
{
this.progressBar.Value = (double)valor;
Thread.Sleep(500);
}
}
En el caso anterior, si ejecutáramos el proceso en forma directa, conseguiríamos que
la interfaz visual quedara completamente bloqueada, en especial por la línea:
Thread.Sleep(500);
07_Silverlight.qxp 9/30/09 1:35 PM Page 259
Esta línea detendrá el hilo de ejecución actual durante medio segundo, por lo que,
por cada iteración del bucle, todo el hilo de ejecución se detendrá. Para este caso, es-
cribimos esa línea sólo para lograr una sensación de trabajo por parte de la aplicación
y no cargar en forma instantánea la barra de progreso. En todo caso, el problema per-
siste ya que seguiremos bloqueando el hilo principal de ejecución, a menos que eje-
cutemos esta función en un hilo diferente, como vemos en el siguiente código:
private void Button_Click(object sender, RoutedEventArgs e)
{
ThreadStart referenciaProceso = new ThreadStart(RealizarProceso);
Thread nuevoHilo = new Thread(referenciaProceso);
nuevoHilo.Start();
}
Como primer paso, creamos un delegado del tipo ThreadStart, el cual recibe como
parámetro el nombre de la función o método que queramos ejecutar de manera asín-
crona. El siguiente paso consiste en crear un nuevo hilo de ejecución mediante el uso
de la clase Thread y asignarle al parámetro requerido el delegado creado previamen-
te. Hasta este punto, sólo hemos creado el ambiente de ejecución del nuevo hilo, por
lo que usaremos el método Start() para iniciar el proceso.
Si ejecutamos el nuevo proceso tal como lo hemos escrito, veremos que obtendremos
un error en la ejecución. Esto se debe a que no es posible, en Silverlight, modificar
elementos de manera directa entre diferentes procesos. Pensemos que la interfaz vi-
sual se está ejecutando en un hilo, como ya hemos podido comprobar, y la función,
ahora, se ejecuta en otro hilo, por lo que estos dos hilos de ejecución no pueden al-
terarse entre ellos. Para poder hacerlo, es necesario dejar que el manejador del hilo
principal se encargue de hacer las actualizaciones correspondientes a los elementos
que pertenezcan a su dominio o estén bajo él.
this.Dispatcher.BeginInvoke((ThreadStart)delegate()
{
this.progressBar.Value = (double)valor;
}
);
El código le avisa, al manejador del hilo, que debe ejecutar la actualización de la barra
de progreso. Para esto, utilizamos otro delegado para crear un método anónimo, el cual
ejecutará la actualización del control cuando el hilo principal pueda procesarlo.
7. INTERCONEXIÓN
260
07_Silverlight.qxp 9/30/09 1:35 PM Page 260
Hilos y eventos
Podemos llegar aún más lejos con Silverlight y el uso de hilos de ejecución si im-
plementamos eventos. Si bien ya estamos familiarizados con los eventos debido
a que hemos hecho uso de ellos con la implementación de botones, listas des-
plegables y otros controles con la capacidad de notificarnos el momento en que
se produce un cambio interno en el control o cuando el usuario interactúa con
él, también es posible crear estos eventos por nuestra cuenta. Esto puede ser es-
pecialmente útil si lo conjugamos con el uso de hilos. De esta forma, podríamos
iniciar un hilo de ejecución para una tarea y hacer que ésta, al finalizar o al su-
ceder diferentes hitos, nos avise de estos hechos para que el código que hubiera
iniciado el nuevo proceso sepa cómo reaccionar basado en estos cambios. Pode-
mos declarar un evento de la siguiente forma:
delegate void delegadoEvento(int valor);
event delegadoEvento eventoHilo;
Notemos que la primera línea es un delegado. Este delegado representa la firma
que deberán tener aquellas funciones o métodos que quieran obtener alguna noti-
ficación por parte del evento. En este caso, la función que implemente este even-
to deberá recibir un valor entero como parámetro de entrada. La siguiente línea es
el evento propiamente dicho, el cual hace uso de la firma provista por el delegado
creado con anterioridad. Si extendemos el ejemplo utilizado para crear nuestros
propios hilos, podríamos asociar la función de actualización de la barra de progre-
so al evento para que, cuando el hilo ejecutado en paralelo ejecute cada iteración,
nos notifique de los cambios realizados por medio del evento.
private delegate void delegadoEvento(int valor);
private event delegadoEvento eventoHilo;
public Page()
Manejo de hilos
261
RRR
Si bien el concepto de delegados es mucho más complejo y profundo, para entenderlo de ma-
nera rápida podemos decir que un delegado es el equivalente a un puntero o apuntador hacia
una función o método. Este delegado es usado, en la mayoría de los casos, para llamar a la fun-
ción apuntada desde otros métodos y procesos.
DELEGADOS
07_Silverlight.qxp 9/30/09 1:35 PM Page 261
{
InitializeComponent();
eventoHilo += new delegadoEvento(Page_eventoHilo);
}
void Page_eventoHilo(int valor)
{
this.Dispatcher.BeginInvoke((ThreadStart)delegate()
{
this.progressBar.Value = (double)valor;
}
);
}
Veamos que concatenamos al evento un delegado que apunta a una función creada
por nosotros y que contiene la actualización de la barra de progreso. Por último, la
función que incluye la iteración es modificada para que dispare este evento.
private void RealizarProceso()
{
for (int i = 0; i  100; i++)
{
eventoHilo(i);
Thread.Sleep(500);
}
}
Los eventos suelen ser una gran ayuda en implementaciones complejas. De cualquier
manera, es necesario tener cuidado cuando trabajemos con eventos, ya que pueden
arrojarnos un error si ninguna función o método se suscribió. Esto quiere decir que,
mientras nadie se suscriba al evento, éste será nulo y, cuando intentemos ejecutarlo, ob-
tendremos un error de referencia no inicializada. Para solucionar este problema, es re-
comendable usar el código que aparece debajo. Así, podremos garantizar que si nadie
se ha suscrito al evento, éste no se disparará y, por ende, no obtendremos un error.
if (eventoHilo != null)
{
eventoHilo(i);
}
7. INTERCONEXIÓN
262
07_Silverlight.qxp 9/30/09 1:35 PM Page 262
Figura 22. Si no se asocia ninguna función
al evento, éste genera un error al intentar ejecutarse.
CONSUMIR SERVICIOS DESDE SILVERLIGHT
Al principio de este capítulo hicimos uso del objeto WebClient para enviar infor-
mación hacía una página web y tomar los resultados arrojados por ella. Pudimos
crear un lector de RSS y también capturar datos desde la página sobre la base de
los datos introducidos por el usuario en nuestra aplicación Silverlight. Si bien
éste puede ser un buen mecanismo para enviar e interactuar con elementos que se
encuentren fuera de nuestra aplicación web, no sirve para cubrir todos los casos
posibles. Pensemos en modelos donde necesitemos agregar mayor seguridad al
transporte de la información o en el que requiramos poder obtener información
en forma de tipos de datos concretos y conocidos por nuestra aplicación. Para
estos casos, es común la implementación de servicios web en los que un sitio,
nuestro o de un tercero, expone en Internet métodos o funciones para procesar
y devolver información. Otras aplicaciones pueden conectarse a estos servicios,
consumir esa información y mostrarla en el ámbito de la misma aplicación, simu-
lando que los datos desplegados fueran generados por ésta, sin tener que enviar al
usuario a una página web distante.
Así como podemos conectarnos a servicios distantes, también es posible consu-
mir información de servicios creados por nosotros y que trabajen en nuestro si-
tios web. Para esto, necesitamos contar con un sitio web; y para ello crearemos
una aplicación Silverlight dejando que Visual Studio cree el sitio web utilizado
para poder depurar y visualizar la aplicación Silverlight. Una vez que tengamos
Consumir servicios desde Silverlight
263
07_Silverlight.qxp 9/30/09 1:35 PM Page 263
nuestra solución creada, en el proyecto web adicionaremos un nuevo servicio
web, como vemos en la figura que aparece a continuación.
Figura 23. Debemos adicionar un nuevo
servicio web a nuestra aplicación ASP.net.
Si no hemos trabajado nunca con servicios web creados con Microsoft .Net, notare-
mos que no existe diferencia alguna con un método o función tradicional del lengua-
je que estemos acostumbrados a usar. De cualquier manera, este método es decorado
con algunos atributos que especifican su alcance, como podemos ver a continuación:
[WebService(Namespace = “http://tempuri.org/”)]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class MiServicioWeb : System.Web.Services.WebService
{
[WebMethod]
public long Sumar(long valor1, long valor2)
{
return valor1 + valor2;
}
}
El atributo decorativo [WebMethod] especifica que la función o método dentro del
servicio web resulta accesible desde Internet o la Web. De esta forma, el método
7. INTERCONEXIÓN
264
07_Silverlight.qxp 9/30/09 1:35 PM Page 264
queda expuesto a las distintas aplicaciones que quieran consumirlo. Para poder
consumir un servicio web, primero necesitaremos saber dónde se encuentra, en la
Web, ese servicio. Sin esta ruta, no podremos acceder a él. En el caso del servicio
web creado previamente, si estamos trabajando de manera local, es posible ver su
dirección al ejecutar el servicio. Por lo general, podremos encontrarlo con el apar-
tado http://localhost que hace referencia a nuestro equipo. El siguiente paso es el
de adicionar esta referencia al servicio dentro de nuestra aplicación Silverlight. Pa-
ra esto, agregaremos una nueva referencia web apuntando al servicio en cuestión,
como vemos en la siguiente figura.
Figura 24. Agregando una referencia de un servicio web a nuestra aplicación Silverlight.
Entre los protocolos de comunicación usados por los servicios web, se encuentra el
llamado SOAP (Simple Object Access Protocol, o en castellano, protocolo de acceso
a objetos simple). Este protocolo sirve para transportar objetos de forma simple en-
tre aplicaciones. Además, se basa en XML para representar los distintos elementos
que se transportarán y, si bien no es el objetivo de este libro profundizar en este pro-
tocolo, sí es necesario mencionar que, en el caso de Silverlight, usaremos SOAP pa-
ra transportar la información entre nuestra aplicación y el servicio web. Una vez
Consumir servicios desde Silverlight
265
,
El uso de Thread.Sleep() en los ejemplos es sólo para ilustrar un comportamiento de carga en
la aplicación. Ya que Thread.Sleep() detiene momentáneamente la ejecución del hilo actual, el
uso en aplicaciones finales podría causar un deterioro en la velocidad de ejecución de ésta.
THREAD.SLEEP()
07_Silverlight.qxp 9/30/09 1:35 PM Page 265
adicionada la referencia al servicio web, podremos verla en el árbol del proyecto. El
servicio creado tiene la finalidad de sumar dos números largos y retornarnos el
resultado de la operación. Para esto, es necesario que primero enviemos estos nú-
meros introducidos por el usuario. Crearemos una interfaz con un par de controles
TextBox, un botón y algunas etiquetas para escribir en ellas.
UserControl x:Class=”Capitulo7ServiciosWeb.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400” Height=”300”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006”
mc:Ignorable=”d”
Grid x:Name=”LayoutRoot” Background=”White”
Button Click=”Button_Click” Margin=”167,30,190,0”
VerticalAlignment=”Top” Content=”Sumar” d:LayoutOverrides=”Width”/
TextBox HorizontalAlignment=”Left” Margin=”8,28,0,0”
VerticalAlignment=”Top” Width=”69” Text=”” TextWrapping=”Wrap”
x:Name=”valor1”/
TextBox HorizontalAlignment=”Left” Margin=”94,28,0,0”
VerticalAlignment=”Top” Width=”69” Text=”” TextWrapping=”Wrap”
x:Name=”valor2”/
TextBlock x:Name=”resultado” HorizontalAlignment=”Left”
Margin=”8,69,0,0” VerticalAlignment=”Top” Text=”Resultado:”
TextWrapping=”Wrap” Width=”155”/
TextBlock HorizontalAlignment=”Left” Margin=”8,8,0,0”
VerticalAlignment=”Top” Width=”177” Text=”Escriba los números a
sumar:” TextWrapping=”Wrap”/
/Grid
/UserControl
7. INTERCONEXIÓN
266
_`
El canal del clima o Weather Channel, posee un servicio web para consulta del clima. Con este
servicio, tendremos la capacidad de desplegar los datos climáticos de cualquier parte del mun-
do en nuestra aplicación. Podemos registrarnos a este servicio de forma gratuita por medio de
su sitio web en www.weather.com/services/xmloap.html.
EL CANAL DEL CLIMA
07_Silverlight.qxp 9/30/09 1:35 PM Page 266
El siguiente paso consiste en tomar los valores introducidos por el usuario, conec-
tarse al servicio web y entregarle estos valores.
private void Button_Click(object sender, RoutedEventArgs e)
{
ServicioSumar.MiServicioWebSoapClient servicio =
new ServicioSumar.MiServicioWebSoapClient();
servicio.SumarCompleted +=
new EventHandlerServicioSumar.SumarCompletedEventArgs
(servicio_SumarCompleted);
servicio.SumarAsync(long.Parse(this.valor1.Text),
long.Parse(this.valor2.Text));
}
Como podemos ver, deberemos realizar tres pasos para poder trabajar con el servicio
web. Primero, crearemos una instancia del servicio ya adicionado como referencia web
a nuestro proyecto. Luego, enlazamos un método o función al evento Completed del
método por ejecutar. Esto es debido a que necesitamos llamar de forma asíncrona al
servicio web, y este evento nos avisará cuando la llamada se haya completado. Por úl-
timo, ejecutamos el evento del servicio pasando los dos valores introducidos por el
usuario. Una vez que el servicio haya realizado de manera correcta el proceso de su-
ma, nos retornará el resultado para que podamos desplegarlo en nuestra aplicación.
void servicio_SumarCompleted(object sender,
ServicioSumar.SumarCompletedEventArgs e)
{
this.resultado.Text = “Resultado: “ + e.Result.ToString();
}
Consumir servicios desde Silverlight
267
RRR
Debido a que los datos transferidos por un servicio web son, típicamente, XML, puede resultar
difícil probar el servicio sin tener que realizar código. Por esto, Microsoft .Net nos provee de una
interfaz web para probar el servicio. Para acceder a ella, sólo tendremos que navegar hasta el
servicio de forma local.
PROBAR SERVICIOS WEB
07_Silverlight.qxp 9/30/09 1:35 PM Page 267
7. INTERCONEXIÓN
268
El objeto e contiene los resultados devueltos por el servicio, por lo que tomamos
de éste la respuesta enviada por el servicio llamado previamente.
Figura 25. Al llamar al servicio enviándole los dos valores introducidos
por el usuario, el servicio realiza el cálculo matemático y retorna el resultado.
Si bien en el ejemplo hemos enviado y recibido tipos de datos primitivos, es posible
también enviar y recibir tipos complejos, como entidades de datos, listas y colecciones
de elementos, entre otros. Para entender esto, crearemos en el proyecto que contiene
el servicio web una entidad para transportar datos de un usuario de la siguiente forma:
public class Usuarios
{
public string Nombre
{ get; set; }
public string Apellido
{ get; set; }
public string Correo
{ get; set; }
}
Esta clase representará los datos de un usuario que trataremos de enviar a la aplica-
ción Silverlight desde el servicio web. Para esto, tendremos que agregar un nuevo
método web que retorne dicha entidad, como vemos a continuación:
07_Silverlight.qxp 9/30/09 1:35 PM Page 268
[WebMethod]
public Usuarios LeerUsuario()
{
return new Usuarios() { Nombre = “Usuario 1”,
Apellido = “Apellido 1”,
Correo = “Correo 1” };
}
De la misma forma que hicimos en el primer ejemplo, deberemos conectarnos al
servicio web, llamar al método que retorne el tipo complejo para luego poder
manipularlo en la aplicación Silverlight.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ServicioSumar.MiServicioWebSoapClient servicio =
new ServicioSumar.MiServicioWebSoapClient();
servicio.LeerUsuarioCompleted +=
new
EventHandlerServicioSumar.LeerUsuarioCompletedEventArgs
(servicio_LeerUsuarioCompleted);
servicio.LeerUsuarioAsync();
}
void servicio_LeerUsuarioCompleted(object sender,
ServicioSumar.LeerUsuarioCompletedEventArgs e)
{
ListServicioSumar.Usuarios usuarios = new
ListServicioSumar.Usuarios();
usuarios.Add(e.Result);
this.grilla.ItemsSource = usuarios;
}
Como el servicio expone el tipo complejo al devolverlo en el método LeerUsuario,
este tipo puede ser usado desde la aplicación Silverlight para reconocer el valor re-
tornado y así capturar los resultados. En la Figura 26, vemos el resultado de llamar
al servicio web, leer el resultado y asignarlo a una grilla de datos.
Consumir servicios desde Silverlight
269
07_Silverlight.qxp 9/30/09 1:35 PM Page 269
Figura 26. La grilla muestra el registro enviado por el servicio web.
Si hacemos uso de las últimas tecnologías propuestas por Microsoft, vale mencio-
nar que Silverlight no sólo puede consumir información de servicios web clásicos,
sino que también puede conectarse y consumir información de servicios WCF
(Windows Communication Foundation). Esta tecnología permite inicializar y hos-
pedar servicios sin la necesidad de contar con un servidor que contenga IIS
(Internet Information Services) para administrar el servicio, como pasaría en el
caso de los primeros servicios web creados en este capítulo.
Crear un servicio WCF
El primer paso para crear nuestro servicio WCF será agregar, al proyecto web creado
junto con nuestra aplicación Silverlight, un servicio del tipo WCF para Silverlight. Lue-
go, debemos seleccionar el tipo de servicio. En este caso, un servicio WCF preparado
para ser consumido desde Silverlight. Este servicio, a diferencia del que ya hemos usa-
do, posee dos atributos nuevos para identificar el servicio y los métodos expuestos:
• ServiceContract: este contrato de servicio, distingue la clase que será expuesta co-
mo un servicio. Esta clase puede contener diferentes métodos expuestos.
• OperationContract: los contratos de operación representan cada uno de los méto-
dos o funciones expuestos por el servicio y con los cuales se podrá interactuar.
[ServiceContract(Namespace = “”)]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
7. INTERCONEXIÓN
270
07_Silverlight.qxp 9/30/09 1:35 PM Page 270
public class ServicioWCF
{
[OperationContract]
public void EscribirMensaje(string mensaje)
{
...
}
}
La segunda parte hace referencia a la configuración y exposición del servicio. Esto
se realiza dentro del archivo de configuración de la aplicación, por lo general, re-
presentado con el nombre App.Config o en un ambiente web como Web.Config.
system.serviceModel
behaviors
serviceBehaviors
behavior name=”Capitulo7WCFService.Web.ServicioWCFBehavior”
serviceMetadata httpGetEnabled=”true” /
serviceDebug includeExceptionDetailInFaults=”false” /
/behavior
/serviceBehaviors
/behaviors
serviceHostingEnvironment aspNetCompatibilityEnabled=”true” /
services
service
behaviorConfiguration=”Capitulo7WCFService.Web.ServicioWCFBehavior”
name=”Capitulo7WCFService.Web.ServicioWCF”
endpoint address=”” binding=”basicHttpBinding”
contract=”Capitulo7WCFService.Web.ServicioWCF” /
endpoint address=”mex” binding=”mexHttpBinding”
contract=”IMetadataExchange” /
/service
/services
/system.serviceModel
Esta configuración define por completo el comportamiento que tendrá el servicio.
Incluye información relacionada con el descubrimiento del servicio por otras apli-
caciones y el detalle de las excepciones que éste arroja. Con el servicio configurado,
sólo nos resta crear la implementación del contrato.
Consumir servicios desde Silverlight
271
07_Silverlight.qxp 9/30/09 1:35 PM Page 271
[ServiceContract(Namespace = “”)]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class ServicioWCF
{
[OperationContract]
public void EscribirMensaje(string mensaje)
{
Debug.WriteLine(mensaje);
return;
}
}
En este caso, todos los mensajes que reciba el servicio serán escritos en la consola de
depuración. De esta forma, comprobaremos que la conexión es exitosa y que los
mensajes están siendo recibidos por el servicio. Podremos verificar previamente que
el servicio se encuentra activo, ejecutando la aplicación web y accediendo a la ruta
donde ese servicio se encuentra alojado, como podemos ver en la Figura 27.
Figura 27. El servicio WCF funciona de manera correcta.
De la misma forma en que adicionamos el servicio web a nuestra aplicación Silverlight,
el servicio WCF debe ser referenciado y adicionado a nuestra aplicación, como po-
demos ver en la Figura 28. El procedimiento es idéntico, y se puede seleccionar el
servicio en cuestión sobre la base de la dirección donde está alojado.
7. INTERCONEXIÓN
272
07_Silverlight.qxp 9/30/09 1:35 PM Page 272
Figura 28. Adicionando el servicio WCF a la aplicación Silverlight.
Una vez adicionado el servicio, notaremos que el archivo de configuración de la
aplicación Silverlight ha sido modificado para especificar la forma en la que ésta
se conectará al servicio WCF. Esta configuración resulta de igual importancia que
la vista anteriormente, ya que ambas deben tener cierta concordancia para que tan-
to la aplicación que consume el servicio como el servicio en sí se comuniquen de
igual forma. Veamos el código necesario para esto:
configuration
system.serviceModel
bindings
basicHttpBinding
binding name=”BasicHttpBinding_ServicioWCF”
maxBufferSize=”2147483647”
maxReceivedMessageSize=”2147483647”
security mode=”None” /
Consumir servicios desde Silverlight
273
RRR
Un método anónimo es una pieza de código que no posee una firma (nombre de función) específi-
ca. Todo el código generado para este método es apuntado por un delegado, el cual representará
el punto de entrada para la ejecución de las líneas creadas dentro de ese método anónimo.
MÉTODOS ANÓNIMOS
07_Silverlight.qxp 9/30/09 1:35 PM Page 273
/binding
/basicHttpBinding
/bindings
client
endpoint address=”http://localhost:2113/ServicioWCF.svc”
binding=”basicHttpBinding”
bindingConfiguration=”BasicHttpBinding_ServicioWCF”
contract=”ServicioWCF.ServicioWCF”
name=”BasicHttpBinding_ServicioWCF” /
/client
/system.serviceModel
/configuration
Cuando ya tenemos todos los elementos configurados, sólo nos resta llamar al
servicio pasándole los parámetros definidos por éste. Notaremos que la forma de
hacerlo es idéntica a la que ya hemos usado.
private void Button_Click(object sender, RoutedEventArgs e)
{
ServicioWCF.ServicioWCFClient servicio = new
ServicioWCF.ServicioWCFClient();
servicio.EscribirMensajeCompleted +=
new
EventHandlerSystem.ComponentModel.AsyncCompletedEventArgs(servicio_
EscribirMensajeCompleted);
servicio.EscribirMensajeAsync(this.textoMensaje.Text);
}
void servicio_EscribirMensajeCompleted(object sender,
System.ComponentModel.AsyncCompletedEventArgs e)
{
}
Si ejecutamos nuestra aplicación Silverlight, podremos ver con claridad cómo los
valores escritos en ésta son enviados al servicio para que, por último, sean escri-
tos en la consola de depuración, como vemos en la siguiente imagen.
7. INTERCONEXIÓN
274
07_Silverlight.qxp 9/30/09 1:35 PM Page 274
Figura 29. Mientras se envían datos desde
Silverlight, el servicio los escribe en la consola de depuración.
De esta forma, hemos podido conectarnos tanto a servicios web tradicionales como
al nuevo modelo de comunicación de Microsoft: Windows Communication
Foundation. El acceso y manipulación de servicios puede sernos de extrema ayuda
en los casos en que necesitemos extender la funcionalidad de Silverlight o inter-
conectarlo con aplicaciones y lenguajes que no estén directamente relacionados
a tecnologías Microsoft. Pensemos en la posibilidad de conectarnos a servicios
creados en lenguajes, como PHP, Java o Ruby, que trabajen en ambientes no re-
lacionados en forma directa con productos Microsoft, como Windows.
MANIPULAR DATOS
En el desarrollo de aplicaciones empresariales, uno de los puntos fuertes es la ma-
nipulación de datos. Cómo capturar y mostrar información desde el usuario y hacia
él, y almacenarla o recuperarla, son algunos de los retos con los que los desarrolla-
dores se enfrentan a cada momento. Por esto, es necesario también poder contar
con formas fáciles y rápidas de realizar estas tareas. Silverlight implementa varías téc-
nicas y modelos que simplifican el desarrollo de aplicaciones orientadas a los datos.
Por un lado, podemos usar el concepto de enlazado de datos, que hace referencia
a que, sobre la base de los datos que tengamos disponibles y de su estructura, po-
damos especificar qué controles y componentes los mostrarán y cómo lo harán, así
como actualizar esta información de vuelta hacia los elementos que originalmente
transportaban esta información. Otra de las posibilidades brindadas es el uso de
Manipular datos
275
07_Silverlight.qxp 9/30/09 1:35 PM Page 275
LinQ. Tras una modificación al lenguaje de programación, se incluye este modelo
que nos brinda la posibilidad de realizar consultas sobre objetos XML o bases de da-
tos, pero desde el punto de vista de la programación orientada a objetos. Esto quie-
re decir que, mediante el uso de sintaxis de programación orientada a objetos, es
posible ejecutar consultas similares a las encontradas en las bases de datos, hacien-
do que los distintos objetos creados por código puedan ser filtrados, ordenados y
agrupados, entre otras posibilidades.
Enlazado de datos
Esta técnica, entonces, se refiere a la posibilidad de que los valores contenidos en
una entidad contenedora de datos puedan ser leídos y mostrados de manera auto-
mática. Decimos que es de forma automática ya que, en los casos más comunes, se
suele leer el valor del origen de datos y asignarlo al elemento de la interfaz que
queramos que muestre esta información.
this.textBoxNombre.Text = persona.Nombre;
this.textBoxApellido.Text = persona.Apellido;
this.textBoxCorreo.Text = persona.Correo;
Si bien las líneas de código vistas no representan un problema, con grandes volúme-
nes de información pueden requerir mucho esfuerzo para su construcción. Además,
pueden incurrir en costos de mantenimiento. Si agregáramos o modificáramos algu-
na de las propiedades del objeto contenedor de datos, tendríamos que cambiar tam-
bién nuestro código. Al mismo tiempo, si necesitáramos hacer que uno de los valores
anteriores se mostrase en otra caja de texto y no en la predefinida en el código, sería
necesario tener que modificar esas líneas y compilar la aplicación otra vez. Para solu-
cionar este problema y asociar los datos a los distintos controles de nuestra interfaz,
podemos utilizar el enlazado de datos en el código XAML, especificando el nombre
de la propiedad del contenedor de datos del cual tomaremos la información:
Text=”{Binding Correo}”
Mediante el uso de la cláusula Binding, acompañada del nombre de la propiedad
de la que se consumirá la información, la propiedad del control asociado toma-
rá este valor y lo aplicará en tiempo de ejecución. Así, si necesitáramos modifi-
car esta información (la fuente del dato), sólo deberíamos cambiar el código
XAML sin necesidad de recompilar toda la aplicación. Veamos cómo podríamos
aplicar esta forma de enlazado de datos en nuestra aplicación:
7. INTERCONEXIÓN
276
07_Silverlight.qxp 9/30/09 1:35 PM Page 276
UserControl x:Class=”Capitulo7DataBinding.Page”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”400” Height=”300”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008”
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006”
mc:Ignorable=”d”
Grid x:Name=”LayoutRoot” Background=”White”
Grid.RowDefinitions
RowDefinition Height=”0.177*”/
RowDefinition Height=”0.187*”/
RowDefinition Height=”0.21*”/
RowDefinition Height=”0.427*”/
/Grid.RowDefinitions
Grid.ColumnDefinitions
ColumnDefinition Width=”0.315*”/
ColumnDefinition Width=”0.685*”/
/Grid.ColumnDefinitions
TextBox Margin=”8,31,82,8” Grid.Column=”1” Grid.Row=”2”
Text=”{Binding Correo}” TextWrapping=”Wrap”
d:LayoutOverrides=”Height”/
TextBox Margin=”8,24,82,8” Grid.Column=”1” Grid.Row=”1”
Text=”{Binding Apellido}” TextWrapping=”Wrap”
d:LayoutOverrides=”Height”/
TextBox Margin=”8,21,82,8” Grid.Column=”1” Text=”{Binding Nombre}”
TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
Button Click=”Button_Click” HorizontalAlignment=”Left”
Margin=”8,0,0,8” VerticalAlignment=”Bottom” Grid.Column=”1”
Grid.Row=”3” Content=”Leer” d:LayoutOverrides=”Height”/
Button Click=”Button_Click_1” HorizontalAlignment=”Left”
Margin=”42,0,0,8” VerticalAlignment=”Bottom” Grid.Column=”1”
Grid.Row=”3” Content=”Guardar”/
TextBlock Margin=”62.594,0,8.161,8” VerticalAlignment=”Bottom”
Text=”Nombre:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
TextBlock Margin=”62.594,0,8.161,8” VerticalAlignment=”Bottom”
Grid.Row=”1” Text=”Apellido:” TextWrapping=”Wrap”
d:LayoutOverrides=”Height”/
TextBlock HorizontalAlignment=”Right” Margin=”0,0,7.717,8”
VerticalAlignment=”Bottom” Width=”55” Grid.Row=”2” Text=”Correo:”
TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
Manipular datos
277
07_Silverlight.qxp 9/30/09 1:35 PM Page 277
/Grid
/UserControl
Notemos que aún no hemos especificado la fuente de datos. Si bien los controles
saben el nombre de la propiedad de la cual obtendrán la información por mostrar,
ésta no ha sido especificada aún. Para lograr esto, podremos asignar el objeto con-
tenedor de datos al control que incluye los controles que configuramos para que
usen enlazado de datos. En este caso, el control Grid es el agrupador de los contro-
les TextBox, y lo usaremos para asignar los datos.
private Persona persona;
public Page()
{
InitializeComponent();
persona = new Persona() {
Nombre = “Persona 1”,
Apellido = “Apellido 1”,
Correo = “Correo 1” };
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.LayoutRoot.DataContext = persona;
}
Si usamos la propiedad DataContext del control Grid, asignamos el objeto de datos
y, como resultado de esta acción, todos los valores serán recolectados y desplega-
dos por los correspondientes controles.
7. INTERCONEXIÓN
278
RRR
Debido a que en un principio asignamos un tipo de dato específico, la propiedad DataContext
retornará el mismo tipo de datos que hemos asignado, lo que nos ahorrará líneas de código al
tener que transformar nuestros objetos a algún otro tipo específico, y viceversa.
DATACONTEXT
07_Silverlight.qxp 9/30/09 1:35 PM Page 278
Figura 30. Valores asignados en forma automática mediante enlazado de datos.
Así como asignamos valores mediante el atributo DataContext, es posible recolectar los
cambios de estos valores por medio de la misma propiedad, como vemos en el código
inferior. Si dejamos el enlazado de datos tal como lo definimos al principio, por más
que el usuario realice cambios en los valores de la interfaz, al tratar de recolectar la in-
formación, éstos valdrán exactamente lo mismo que en el momento de la asignación.
persona = (Persona)this.LayoutRoot.DataContext;
Figura 31. Los datos fueron actualizados en la interfaz,
pero la propiedad DataContext retornó valores no actualizados.
Manipular datos
279
07_Silverlight.qxp 9/30/09 1:35 PM Page 279
Esto se debe a que es posible especificar la forma en la que los controles con datos en-
lazados se comportarán ante los cambios. Configuramos el enlace de datos con alguna
de las siguientes propiedades basados en el comportamiento que queramos obtener:
• OneWay: éste es el valor por defecto. Hará que el control enlazado modifique su
valor sólo cuando la fuente de datos sea modificada.
• TwoWay: actuará tanto cuando la fuente de datos sea modificada así como cuan-
do el control sufra un cambio. De esta forma, si el usuario modificara el texto des-
plegado en un control, este cambio se vería reflejado en la fuente de datos.
• OneTime: sólo actualizará los controles la primera vez que se asignen los valores
desde la fuente de datos. Luego, no se verán afectados por cambios en la fuente
de datos y tampoco ejercerán cambios sobre ella.
Si hacemos una modificación a nuestros controles enlazados, actualizaremos los valo-
res de la fuente de datos sobre la base de las modificaciones realizadas por el usuario.
TextBox Margin=”8,31,82,8” Grid.Column=”1” Grid.Row=”2” Text=”{Binding
Correo, Mode=TwoWay}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
TextBox Margin=”8,24,82,8” Grid.Column=”1” Grid.Row=”1” Text=”{Binding
Apellido, Mode=TwoWay}” TextWrapping=”Wrap”
d:LayoutOverrides=”Height”/
TextBox Margin=”8,21,82,8” Grid.Column=”1” Text=”{Binding Nombre,
Mode=TwoWay}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/
Figura 32. En este caso, los datos fueron actualizados
en la interfaz, y la propiedad DataContext retornó valores actualizados.
7. INTERCONEXIÓN
280
07_Silverlight.qxp 9/30/09 1:35 PM Page 280
En el ejemplo anterior hemos usado, como tipo de dato base para todos los valo-
res, un string o texto, pero esto no siempre será de esta manera, ya que a veces se
necesitan otro tipo de valores para albergar, por ejemplo, datos numéricos, fechas
y demás. Si enlazáramos datos diferentes al de texto y el usuario introdujera un va-
lor no soportado por ese tipo de datos, por ejemplo, un campo numérico para alo-
jar el precio de un producto, y el usuario escribiera una letra, obtendríamos un
error en la aplicación. Esto se debe a que, al tratar de pasar los valores de la inter-
faz a la entidad asignada, los tipos de datos colapsarían. Para evitar esto, podemos
hacer uso de validadores en el enlazado de datos que, si bien no prevendrán del
error, sí nos avisarán para que nosotros tomemos un curso de acción para solucio-
narlo. Tengamos en cuenta la siguiente entidad de datos:
public class Persona
{
public string Nombre
{ get; set; }
public string Apellido
{ get; set; }
public string Correo
{ get; set; }
public int Edad
{ get; set; }
}
Adicionamos el campo Edad, de tipo numérico. En este caso, si el usuario colocase
un valor no numérico, produciría un error al no poder pasar ese valor a uno que só-
lo acepta números. Lo primero que haremos es agregar un nuevo control TextBox
para desplegar un valor numérico desde la fuente de datos.
TextBox Margin=”8,25,82,80” Grid.Column=”1” Grid.Row=”3” Text=”{Binding
Edad, Mode=TwoWay, ValidatesOnExceptions=true,
NotifyOnValidationError=true}” TextWrapping=”Wrap”
d:LayoutOverrides=”Height”/
Veamos que, en la propiedad Text del control, dentro de la declaración del en-
lazado de datos previamente usada, ahora hemos agregado dos nuevos atributos:
Manipular datos
281
07_Silverlight.qxp 9/30/09 1:35 PM Page 281
ValidatesOnExceptions, que hará las validaciones en relación con lo introducido por el
usuario y el tipo de dato de la fuente de datos; y NotifyOnValidationError, que dispara-
rá un evento para notificar que se ha producido un error de validación. Debido a que
hemos asignado la fuente de datos al contenedor de estos controles, es necesario decla-
rar y capturar el evento disparado por el validador desde este punto.
Grid x:Name=”LayoutRoot” Background=”White”
BindingValidationError=”LayoutRoot_BindingValidationError”
Grid.RowDefinitions
...
Notemos la presencia de BindingValidationError. Este evento es el que nos avisará
en el momento que alguna validación falle. Gracias a esto, podremos avisar al usua-
rio que existe un problema para que haga los cambios correpondientes.
private void LayoutRoot_BindingValidationError(object sender,
ValidationErrorEventArgs e)
{
this.mensajeError.Text = “Se encontró un error en los datos.”;
this.mensajeError.Text += “ Valor: “ +
((System.Windows.Controls.TextBox)(((System.Windows.RoutedEventArgs)
(e)).OriginalSource)).Text;
}
Figura 33. Error de validación capturado y mensaje enviado al usuario.
7. INTERCONEXIÓN
282
07_Silverlight.qxp 9/30/09 1:35 PM Page 282
Manipular datos
283
LinQ
LinQ es una modificación a los lenguajes de programación basados en Microsoft .Net
Framework 3.5, que permite realizar consultas sobre XML, objetos y bases de datos
simulando la sintaxis de SQL transaccional con palabras reservadas y un enfoque orien-
tado a objetos. Es destacable la presencia de LinQ en Silverlight ya que, por el peque-
ño tamaño de la firma instalable en el navegador del cliente, sería válido asumir que
sólo contendrá funcionalidad mínima y que no podría incluir este tipo de aditamen-
tos. Contar con esta clase de herramientas que pueden maximizar la productividad en
el desarrollo hace que, una vez más, Silverlight esté listo para aplicaciones de gran escala.
Para ver la potencia de LinQ, asumamos que necesitamos ordenar una lista de ele-
mentos en un vector. Si bien contamos con mecanismos propios de .Net Framework,
podría existir la posibilidad de que tengamos que implementar nuestra propia forma
de ordenamiento. Una de las más conocidas es el ordenamiento de burbuja.
static void Ordenamiento_Burbuja(int[] array)
{
long maximo_derecho = array.Length - 1;
do
{
long ultimo_cambio = 0;
for (long i = 0; i  maximo_derecho; i++)
{
if (array[i]  array[i + 1])
{
int temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
ultimo_cambio = i;
}
}
maximo_derecho = ultimo_cambio;
}
while (maximo_derecho  0);
}
La función antes planteada ordenará un vector de enteros, que tendrá como única
tarea posible realizar este trabajo. Ahora veamos lo que podríamos lograr con LinQ:
07_Silverlight.qxp 9/30/09 1:35 PM Page 283
int[] vector = new int[] { 10, 4, 5, 35, 23, 56 };
private void Button_Click(object sender, RoutedEventArgs e)
{
var q = from c in vector
orderby c ascending
select c;
this.Ordenado.ItemsSource = q;
}
Si tenemos el mismo vector de números enteros, sólo ejecutamos una consulta sobre
ese vector, ordenándolo de manera ascendente y asignándolo a un control ListBox. Co-
mo podemos ver, para lograr el mismo resultado, la cantidad de código comparado con
el ordenamiento por burbuja típico es sustancialmente menor y más fácil de entender.
Figura 34. Un vector de enteros ordenado con LinQ.
Pero LinQ puede ir mucho más lejos y no sólo ordenar vectores simples. Teniendo
en cuenta que, a pesar de la reducción del volumen de código, la lógica para orde-
nar el vector suele ser genérica, LinQ provee otras características sobre una colección
de elementos o de objetos. Podríamos tener un tipo complejo como el que sigue:
public class Estudiante
{
public enum Cursos
7. INTERCONEXIÓN
284
07_Silverlight.qxp 9/30/09 1:35 PM Page 284
{
A,
B,
C
}
public string Nombre
{ get; set; }
public string Materia
{ get; set; }
public Cursos Curso
{ get; set; }
public string Ciudad
{ get; set; }
public int Nota
{ get; set; }
}
Esta entidad posee diferentes elementos complejos como para invalidar el uso del
ordenamiento por burbuja que habíamos visto inicialmente, sin tener que modi-
ficarlo casi por completo. De cualquier manera, con LinQ podríamos solucionar
este problema de forma sencilla.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var q = from c in estudiantes
where (c.Curso == Estudiante.Cursos.A) 
(c.Nota = 4)
orderby c.Nota descending
select c;
this.grillaAlumnos.ItemsSource = q;
}
En este caso, de una lista de la entidad Estudiante, seleccionamos sólo los alumnos
pertenecientes al curso A con una nota superior a 4, y ordenamos el resultado
Manipular datos
285
07_Silverlight.qxp 9/30/09 1:35 PM Page 285
basados en la nota de manera descendente. Como vemos en la siguiente figura, el
resultado son los alumnos con el criterio de selección previamente formulado.
Figura 35. Lista de estudiantes filtrada con LinQ.
Podemos realizar tantas combinaciones en consultas como si se tratase de una consul-
ta a una base de datos. A continuación, vemos cada una de las palabras reservadas que
podemos usar para obtener información de nuestras colecciones de datos:
• Where: condicionante basado en el predicado de la consulta.
• Select/SelectMany: operador de proyección basado en el predicado de la consulta. Se-
lecciona los elementos resultantes de la consulta como su pariente transaccional.
• Take/Skip/TakeWhile/SkipWhile: operadores de partición basados en una posición
o en el predicado de la consulta.
• Join/GroupJoin: conjunción de dos o más elementos dentro de la consulta ba-
sados en una llave común.
• Concat: operador de concatenación.
• OrderBy/ThenBy/OrderByDescending/ThenByDescending: operadores de ordena-
miento, tanto ascendentes como descendentes.
• Reverse: operador de ordenamiento que se encarga de revertir el orden de la se-
cuencia original de la consulta.
• GroupBy: agrupador de elementos basado en una llave de la consulta.
• Distinct: operador que remueve los elementos duplicados de la consulta.
• Union/Intersect: operadores que se ocupan de retornar la unión o la intersección
de los elementos en la consulta.
• Sum/Min/Max/Average: operadores utilizados para hacer cálculos matemáticos o
de comportamiento dentro de la consulta.
7. INTERCONEXIÓN
286
07_Silverlight.qxp 9/30/09 1:35 PM Page 286
Estos operadores pueden ser aplicados a cualquier lista de objetos o a cualquier ele-
mento que soporte la interfaz IEnumerable. Los resultados obtenidos con LinQ
pueden ser moldeables. Con esto queremos decir que no es necesario que, tras
cada consulta, retornemos un nuevo conjunto de elementos de la misma entidad
filtrada. Es posible, con LinQ, retornar sólo los campos de la entidad que necesite-
mos para ese momento, como podemos ver en el siguiente ejemplo:
private void Button_Click_2(object sender, RoutedEventArgs e)
{
var q = from c in estudiantes
where (c.Materia == “Matematica”)
select new { c.Nombre, c.Materia };
this.grillaAlumnos.ItemsSource = q;
}
En el ejemplo anterior, el resultado sólo contendrá los nombres y las materias de los
estudiantes que cumplan con el criterio de búsqueda, pero no se incluirán los de-
más elementos de la entidad. LinQ tiene mucho potencial, por lo que no debere-
mos desestimarlo en nuestros desarrollos. Si bien aquí sólo hemos visto la punta de
lo que LinQ tiene para ofrecernos, a medida que lo pongamos en práctica recono-
ceremos que podemos lograr cosas bastante complejas con muy poco código.
Manipular datos
287
… RESUMEN
Este capítulo nos ha terminado de mostrar la potencia de Silverlight cuando le agregamos có-
digo C#. Hemos modificado el estado de los controles y componentes para que se comporten
de distintas formas desde el código, aprendimos a guardar y a leer información del usuario,
enviamos y recibimos información por medio de la red con un lector RSS, y utilizamos tecno-
logías de conexión y transporte de datos para consumir información distante. Así, Silverlight
orientado a animaciones y comportamiento visual se transforma en un Silverlight para el de-
sarrollo de aplicaciones web de alto nivel.
07_Silverlight.qxp 9/30/09 1:35 PM Page 287
288

PREGUNTAS TEÓRICAS
1 ¿En qué casos deberemos usar el objeto
WebClient?
2 ¿Qué evento del objeto WebClient debere-
mos usar si queremos saber el progreso de
la descarga del elemento por consumir
desde nuestra aplicación Silverlight 2?
3 ¿Qué versión del lenguaje C# y de Microsoft
.Net Framework podemos utilizar en las
aplicaciones Silverlight 2?
4 ¿Qué es un HTTPHandler?
5 ¿Cuál es el concepto detrás del almacena-
miento aislado?
6 ¿Cómo podemos adquirir mayor capacidad
de almacenamiento dentro del área designa-
da para cada usuario en el almacén aislado?
7 En el almacenamiento aislado, ¿sólo se
pueden guardar archivos?
8 ¿Por qué no es posible modificar la interfaz
gráfica de la aplicación Silverlight 2 desde
un segundo hilo de ejecución?
9 ¿Es posible interactuar con tipos comple-
jos retornados por servicios web desde
Silverlight 2?
10¿Es posible en Silverlight 2 enlazar datos
desde fuentes de datos de forma dinámica?
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Intente ampliar el ejemplo de utilización de
LinQ, incorporando controles XAML con la
lista de filtros y permitirle al usuario inte-
ractuar con los datos y las búsquedas.
2 Para saber más sobre Windows Communi-
cation Foundation, ingrese en http://msdn.
microsoft.com y busque información.
3 Cree un modelo de objetos propio para
almacenar información. Recolecte esa
información ingresada por el usuario y
envíela a un servicio web para que éste se
encargue de almacenarla en una base de
datos distante.
4 Haciendo uso de eventos e hilos de ejecu-
ción, cree un temporizador personalizado.
5 Para saber más sobre el manejo de hilos de
ejecución, ingrese en el sitio web oficial de
MSDN: http://msdn.microsoft.com/es-es.
07_Silverlight.qxp 9/30/09 1:35 PM Page 288
El navegador
y su dominio
Conectar tecnologías 290
Silverlight 2 y el HTML 290
HtmlDocument y HtmlElement 292
HtmlPage 300
HtmlWindow 305
Cookies 314
Modificar CSS 317
Silverlight 2 y JavaScript 320
Llamar funciones 323
Objetos Silverlight
para JavaScript 324
Resumen 327
Actividades 328
Capítulo 8
El navegador web es el centro neurálgico
de ejecución de Silverlight,
que es hospedado por éste junto
con otros lenguajes y tecnologías.
JavaScript, HTML y ASP.net son algunos
de los modelos que viven a través
de nuestro navegador, y pueden
ser conectados entre sí. En este capítulo
haremos que Silverlight interactué
con estas tecnologías comunes.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
08_Silverlight.qxp 9/30/09 1:36 PM Page 289
CONECTAR TECNOLOGÍAS
En el entorno del navegador web, trabajan diferentes tecnologías y lenguajes. Por
ejemplo JavaScript, un lenguaje interpretado y ejecutado por el navegador que faci-
lita desde la generación de contenido dinámico hasta validaciones de las entradas del
usuario. Junto con JavaScript, podemos encontrar el lenguaje de etiquetas que da vi-
da a la Web, el HTML, así como otras tecnologías tales como las hojas de estilo o el
uso de XML. Todo esto es administrado por el navegador del usuario cada vez que
éste accede y visualiza una página web. Por supuesto, Silverlight también es parte de
este entorno, ya que trabaja dentro del navegador del cliente y convive con las tecno-
logías antes mencionadas. El hecho de que Silverlight conviva con otras tecnologías
web hace que sea natural encontrarse con la posibilidad de que este software pueda
influir e interactuar con ellas, así como éstas podrían, también, modificar el compor-
tamiento de la aplicación Silverlight creada y hospedada en este entorno común. Así
es cómo Silverlight provee una serie de objetos que nos permiten interactuar con nues-
tras páginas web, desde dentro de la aplicación Silverlight, y al mismo tiempo, su in-
térprete, instalado en el navegador cliente y que hace uso del lenguaje JavaScript, per-
mite crear y modificar aplicaciones Silverlight desde fuera de su contenedor. En este
capítulo veremos, entonces, cómo es posible interactuar con Silverlight desde fuera de
él y cómo éste, a su vez, puede modificar el ambiente que lo contiene.
SILVERLIGHT 2 Y EL HTML
Silverlight posee una serie de objetos, clases y componentes que nos permiten in-
teractuar con el entorno donde está contenido. En este caso específico, con el
HTML de la página web que contiene nuestra aplicación web. Si tenemos en cuen-
ta que la aplicación Silverlight creada se declara en el código HTML por medio de
tags que el navegador entienda, entonces la aplicación es un elemento más de to-
do el conjunto de elementos que representan la página web. Si vemos el código
HTML declarativo usado para incrustar aplicaciones Silverlight en HTML, nos
daremos cuenta de que este elemento es uno más en el conjunto de tags.
div id=”silverlightControlHost”
object data=”data:application/x-silverlight-2,” type=”application/x-
silverlight-2” width=”100%” height=”100%”
param name=”source” value=”ClientBin/Capitulo8HTML.xap”/
param name=”onerror” value=”onSilverlightError” /
param name=”background” value=”white” /
8. EL NAVEGADOR Y SU DOMINIO
290
08_Silverlight.qxp 9/30/09 1:36 PM Page 290
param name=”minRuntimeVersion” value=”2.0.31005.0” /
param name=”autoUpgrade” value=”true” /
a href=”http://go.microsoft.com/fwlink/?LinkID=124807”
style=”text-decoration: none;”
img src=”http://go.microsoft.com/fwlink/?LinkId=108181”
alt=”Get Microsoft Silverlight” style=”border-style: none”/
/a
/object
iframe style=’visibility:hidden;height:0;width:0;border:0px’/iframe
/div
El código anterior nos muestra que, para que el navegador web pueda mostrar y eje-
cutar la aplicación Silverlight, ésta debe ser declarada en el lenguaje que el navega-
dor entienda, esto es, HTML, y, por consiguiente, será posible acceder a este HTML
desde la aplicación Silverlight. A continuación, podemos ver la lista de clases y ob-
jetos disponibles desde Silverlight para interactuar con nuestra página HTML.
• HtmlPage: identifica la página HTML actual. Según dónde esté incrustado el control
Silverlight, su contexto HTML es representado por este objeto. Este objeto provee
las principales funcionalidades para interactuar con la página web actual, como cap-
turar información del navegador en el que está corriendo la aplicación, abrir venta-
nas emergentes, conocer configuraciones de seguridad del navegador, entre otras.
• BrowserInformation: retorna información específica del navegador, como el tipo de
navegador que se está usando, el nombre del navegador web, su versión, etcétera.
• HtmlDocument: representa la página HTML, su estructura y tags. HtmlDocument
puede ser útil en momentos en los que necesitemos modificar los elementos con-
tenidos en nuestra página web.
• HtmlElement: puede ser cualquier elemento HTML contenido en la página web.
Se pueden usar métodos como SetAttribute() y SetProperty() para modificar cada
elemento, pasando u obteniendo valores al elemento y desde él.
• HtmlWindow: representa la ventana del navegador, proporcionando métodos para na-
vegar a otras páginas o saltar entre diferentes marcadores dentro de la misma página.
• HttpUtility: nos otorga un conjunto de herramientas de código para realizar tare-
as sobre el HTML. Codificar y decodificar los parámetros enviados desde la pá-
gina original hacia una página destino.
• ScriptableTypeAttribute/ScriptableMemberAttribute: atributos que pueden ser aplica-
dos a nuestras clases en Silverlight para hacerlas accesibles desde código JavaScript.
• ScriptObject: referencia una función JavaScript escrita y ejecutada en la página web
contenedora de la aplicación Silverlight. Esta referencia puede ser ejecutada desde
nuestra aplicación Silverlight para realizar acciones fuera del contexto de Silverlight.
Silverlight 2 y el HTML
291
08_Silverlight.qxp 9/30/09 1:36 PM Page 291
HtmlDocument y HtmlElement
Con HtmlDocument es posible modificar e interactuar con la estructura HTML pre-
sente en el documento que albergue la aplicación Silverlight. El siguiente código lee la
dirección web desde el navegador y la muestra dentro de nuestra aplicación Silverlight:
private void Mostrarpagina_Click(object sender, RoutedEventArgs e)
{
HtmlDocument document = HtmlPage.Document;
this.texto1.Text = document.DocumentUri.ToString();
}
Como podemos observar en la Figura 1, la dirección URL donde se ubica la aplica-
ción web es mostrada en un TextBox.
Figura 1. Dirección URL donde se hospeda la aplicación Silverlight.
HtmlDocument no sólo nos otorga algunos datos del navegador y la página web en
la cual estemos ejecutando nuestra aplicación, también nos permite acceder a los
elementos que estén fuera de nuestra aplicación. Veamos el siguiente código HTML:
body style=”height: 100%; margin: 0;”
form id=”form1” runat=”server” style=”height: 100%;”
asp:ScriptManager ID=”ScriptManager1” runat=”server”
/asp:ScriptManager
div style=”height: 100%;”
table
8. EL NAVEGADOR Y SU DOMINIO
292
08_Silverlight.qxp 9/30/09 1:36 PM Page 292
tr
td style=”width:500px; height:300px;”
asp:Silverlight ID=”Xaml1” runat=”server”
Source=”~/ClientBin/Capitulo8HTML.xap”
MinimumVersion=”2.0.31005.0” Width=”100%”
Height=”100%” /
/td
/tr
tr
td
input type=”text” id=”textBoxExterno” value=”” /
/td
/tr
/table
/div
/form
/body
Como podemos observar en el código HTML que aparece más arriba, nuestra apli-
cación Silverlight se encuentra dentro de una tabla HTML y, en el fondo de ella,
un campo de texto declarado con tags HTML.
Figura 2. La aplicación Silverlight dentro de una tabla HTML.
Si nos basamos en la estructura anterior, donde hay un elemento HTML fuera de la
aplicación, es posible que accedamos a ese elemento para modificar sus valores.
Silverlight 2 y el HTML
293
08_Silverlight.qxp 9/30/09 1:36 PM Page 293
private void Button_Click(object sender, RoutedEventArgs e)
{
HtmlDocument documento = HtmlPage.Document;
this.texto2.Text =
documento.GetElementById(“textBoxExterno”).GetAttribute(“value”).ToString();
}
Mediante el uso de GetElementById, palabra reservada homónima de JavaScript,
accedemos al elemento creado por tags HTML en la página, haciendo uso del va-
lor incluido en el atributo ID del componente. Luego, usando GetAttribute, refe-
renciamos el atributo del elemento que contenga los valores por capturar. Como
vemos en la figura siguiente, el contenido de la caja de texto HTML es pasado
dentro de nuestra aplicación Silverlight.
Figura 3. El valor de la caja de texto HTML es capturado por la aplicación Silverlight.
Si hacemos uso de la misma técnica, podemos realizar la acción inversa: enviar
información a cualquier elemento contenido dentro de la página web donde re-
sida nuestra aplicación Silverlight.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
HtmlDocument documento = HtmlPage.Document;
documento.GetElementById(“textBoxExterno”).SetAttribute(“value”, “Valor
enviado desde Silverlight”);
}
8. EL NAVEGADOR Y SU DOMINIO
294
08_Silverlight.qxp 9/30/09 1:36 PM Page 294
En este caso, el texto utilizado en SetAttribute será alojado en la caja de texto
HTML, fuera de la aplicación Silverlight.
Figura 4. En este caso, la caja de texto HTML fue modificada desde Silverlight.
Pero este tipo de atributos no sólo sirve para modificar o leer valores de los con-
troles HTML de la página web. El comportamiento, por el contrario, es más cer-
cano al que podría brindar JavaScript, ya que muchas propiedades no comunes
en el tag HTML, pero que sí pueden ser accedidas desde JavaScript, también
pueden ser accedidas y modificadas desde Silverlight. Agreguemos una fila más
a la tabla HTML previamente creada.
tr
td
div id=”constructorHTML”
/div
/td
/tr
Como vemos, hemos agregado una etiqueta div. Esta etiqueta tiene la particula-
ridad de servir de contenedor de otras etiquetas HTML y, como tal, también es po-
sible modificar su estructura HTML desde código JavaScript mediante el uso de la
propiedad innerHTML. Entonces, podríamos hacer uso de innerHTML desde la apli-
cación Silverlight para crear código HTML dentro de esta etiqueta.
private void Button_Click_2(object sender, RoutedEventArgs e)
Silverlight 2 y el HTML
295
08_Silverlight.qxp 9/30/09 1:36 PM Page 295
{
HtmlDocument documento = HtmlPage.Document;
string constructor = “Introducir nombre: input type=”text”
value=”” id=”nuevoTexto” style=”width:150px””;
documento.GetElementById(“constructorHTML”).SetAttribute(“innerHTML”,
constructor);
}
Como vemos en el código, construimos elementos HTML sobre la base de una ca-
dena de texto que luego es asignado al atributo innerHTML del tag div, haciendo
que este texto sea transformado en HTML.
Figura 5. La nueva caja de texto, con un texto descriptivo creado desde Silverlight.
Como este elemento es creado dentro del conjunto de elementos HTML que con-
forman la página web, no sería impedimento, mediante el uso de GetAttribute y el
identificador del nuevo control, para recuperar esta información una vez que el usua-
rio hubiera completado el campo de texto.
En caso de que tengamos que realizar una aplicación que no sólo trabaje con navega-
dores de la gama de Internet Explorer, podemos hacer uso de otros mecanismos para
crear controles de manera dinámica. Por ejemplo, mediante el uso de HtmlElement, ob-
jetoquepermitelamanipulacióndeelementosindividualesdentrodelapáginaHTML.
private void Button_Click_3(object sender, RoutedEventArgs e)
{
8. EL NAVEGADOR Y SU DOMINIO
296
08_Silverlight.qxp 9/30/09 1:36 PM Page 296
HtmlDocument documento = HtmlPage.Document;
HtmlElement elemento = documento.CreateElement(“INPUT”);
elemento.SetProperty(“type”, “text”);
elemento.SetProperty(“value”, “Nuevo control”);
documento.GetElementById(“constructorHTML”).AppendChild(elemento);
}
Veamos que, en el caso anterior, es necesario definir cada uno de los atributos que
representarán el objeto HTML por crear. Inicialmente creamos un elemento de un
tipo específico, un tipo INPUT, tag usado, por lo común, para definir elementos
con los cuales el usuario pueda interactuar. El siguiente paso es definir el tipo de con-
trol contemplado dentro de este tag y, por último, definimos un valor por defecto
que se visualizará, al comienzo, cuando el control se cree en la página web. Por
último, adicionamos este nuevo control a la lista de controles hijo del tag div
con el que antes habíamos estado interactuando.
Figura 6. Un nuevo control de texto creado mediante el uso de HtmlElement.
De cualquier manera, no estamos sujetos a crear sólo elementos, como botones o
cajas de texto, ya que es posible lograr cualquier elemento HTML representado por
un tag. El siguiente código muestra cómo crear una imagen siguiendo el mismo pa-
trón de creación de elementos HTML:
private void Button_Click_4(object sender, RoutedEventArgs e)
{
Silverlight 2 y el HTML
297
08_Silverlight.qxp 9/30/09 1:36 PM Page 297
HtmlDocument documento = HtmlPage.Document;
HtmlElement elemento = documento.CreateElement(“IMG”);
elemento.SetProperty(“src”,
“http://static.redusers.com.ar/redusers/images/logo.jpg”);
documento.GetElementById(“constructorHTML”).AppendChild(elemento);
}
Figura 7. Al presionar el botón en Silverlight, se crea
una nueva imagen basada en los parámetros establecidos.
Otra posibilidad que otorga el objeto HtmlDocument es la de enviar hacia el servi-
dor toda la información contenida dentro de las etiquetas form de la página web.
Por lo general, usamos estas etiquetas para enmarcar todos los controles web cuyo
contenido será enviado al servidor para que luego éste capture la información in-
troducida por el usuario. Para entender esto, veamos el siguiente código HTML:
form id=”form1” runat=”server” style=”height: 100%;”
asp:ScriptManager ID=”ScriptManager1” runat=”server”
/asp:ScriptManager
div style=”height: 100%;”
...
...
/div
/form
8. EL NAVEGADOR Y SU DOMINIO
298
08_Silverlight.qxp 9/30/09 1:36 PM Page 298
Todos los elementos contenidos dentro de las etiquetas form son capturados por
la página y enviados al servidor para su procesamiento. Así, un usuario que hubie-
se interactuado con cajas de texto, listas desplegables y otros controles podría no-
tificar de estos cambios al código que se ejecuta en el servidor. En el caso de
ASP.net, es posible analizar estos elementos desde el código creado en el servidor.
Ese código podría ser como el que sigue:
script runat=”server”
protected void Page_Load(object sender, EventArgs e)
{
}
/script
En el momento en el que el formulario sea enviado desde el cliente al servidor,
este método ASP.net se disparará y, si bien el usuario deberá realizar la acción de
enviar esta información, también es posible hacerlo desde Silverlight.
private void Button_Click_5(object sender, RoutedEventArgs e)
{
HtmlDocument documento = HtmlPage.Document;
documento.Submit();
}
Al ejecutar la línea documento.Submit(), el formulario se enviará al servidor como ve-
mos en la Figura 8 y en la Figura 9, donde el campo de texto, al final de la aplicación
Silverlight, contiene cierta información introducida por el usuario. Esta información,
luego, es enviada y capturada por el código ASP.net.
Silverlight 2 y el HTML
299
,
La propiedad innerHTML sólo es válida en navegadores compatibles con Internet Explorer,
debido a que Microsoft agregó esta funcionalidad al conjunto de sentencias disponibles para
JavaScript bajo Internet Explorer. Si usamos innerHTML para nuestros desarrollos, podríamos
obtener un error en tiempo de ejecución si el usuario utilizase un navegador no compatible.
INNERHTML
08_Silverlight.qxp 9/30/09 1:36 PM Page 299
Figura 8. Caja de texto modificada por el usuario.
Figura 9. El valor de la caja de texto es capturado en el servidor
una vez que se envía la información desde la aplicación Silverlight.
HtmlPage
El objeto HtmlPage también provee una serie de métodos y funciones para interactuar
sobre la página web donde Silverlight reside. Si bien hemos utilizado este objeto para
obtener una referencia al documento que representa el HTML de la página, HtmlPage
se encuentra en un nivel superior y representa toda la información de la página en
sí, pudiendo generar comportamientos en el navegador. Uno de ellos está ligado a la
creación de ventanas emergentes. Las ventanas emergentes son aquellas que, al ingre-
sar en un sitio o por medio de alguna acción del usuario, son disparadas en una nueva
instancia del navegador web, apareciendo una segunda ventana que nos redirige a otra
8. EL NAVEGADOR Y SU DOMINIO
300
08_Silverlight.qxp 9/30/09 1:36 PM Page 300
página. Con el uso de HtmlPage, es posible generar este comportamiento. La creación
de una ventana emergente posee características similares a las presentadas en el código
JavaScript. Veamos el siguiente código para entender mejor lo que queremos lograr.
script language=”javascript” type=”text/javascript”
function AbrirVentana()
{
var opciones = “width=300; height=300;”;
window.open(“http://www.redusers.com”, “nuevaVentana”, opciones);
}
/script
Notaremos que para crear una nueva ventana es necesario, como primer parámetro,
definir la dirección web a la cual navegará esa ventana, un nombre que la identifique
y una serie de parámetros que definirán su comportamiento. Como resultado, obten-
dremos una nueva instancia del navegador, como vemos en la siguiente figura:
Figura 10. Una ventana emergente desde JavaScript.
Si entendemos este concepto, veremos que la forma de realizar esto desde Silverlight
es similar. Veamos el código:
HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions();
opciones.Width = 300;
Silverlight 2 y el HTML
301
08_Silverlight.qxp 9/30/09 1:36 PM Page 301
opciones.Height = 300;
HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”,
opciones);
El resultado de este código será idéntico al obtenido con JavaScript, donde tam-
bién deberemos definir una dirección URL, el nombre de la nueva instancia y una
serie de opciones para configurar la ventana emergente. Las opciones de configu-
ración de la ventana emergente pueden ser importantes a la hora de obtener un
comportamiento visual específico. Podemos ver la lista de opciones dentro del ob-
jeto HtmlPopupWindowOptions a continuación:
• Height: determina el alto de la ventana en pixeles.
• Width: determina el ancho de la ventana en pixeles.
• Top: establece la posición, en pixeles, de la ventana emergente a partir del borde
superior de la pantalla.
• Left: establece la posición, en pixeles, de la ventana emergente a partir del bor-
de izquierdo de la pantalla.
• Directories: esta opción muestra u oculta los marcadores o vínculos del nave-
gador para la ventana emergente.
• Location: muestra u oculta la barra de navegación para la ventana emergente.
• Menubar: muestra u oculta las opciones del navegador (menús).
• Resizeable: permite la capacidad de que el usuario pueda cambiar, o no, de tama-
ño la ventana emergente una vez creada.
• Scrollbars: esta opción muestra u oculta las barras de desplazamiento, tanto ho-
rizontales como verticales.
• Status: muestra u oculta la barra de estado del navegador.
• Toolbar: esta opción muestra u oculta la barra de herramientas del navegador
en la ventana emergente.
Aplicamos los atributos anteriores como en el siguiente código:
HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions();
opciones.Directories = false;
opciones.Height = 300;
opciones.Left = 10;
opciones.Location = false;
opciones.Menubar = false;
opciones.Resizeable = false;
opciones.Scrollbars = false;
8. EL NAVEGADOR Y SU DOMINIO
302
08_Silverlight.qxp 9/30/09 1:36 PM Page 302
opciones.Status = false;
opciones.Toolbar = false;
opciones.Top = 50;
opciones.Width = 300;
HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”,
opciones);
Figura 11. La posición y las propiedades configuradas en una nueva ventana.
Debido a que las ventanas emergentes suelen ser intrusivas, o no necesariamente acep-
tadas por todos los usuarios, los navegadores actuales cuentan con mecanismos para
bloquear estas ventanas, haciendo que no puedan abrirse a menos que el usuario espe-
cifique lo contrario. Debido a esto, si ejecutamos el código en forma directa y el nave-
gador del cliente cuenta con una herramienta de bloqueo de ventanas emergentes,
no podremos lanzar esta ventana y, por consiguiente, la funcionalidad que pudiéramos
haber querido implementar se vería frenada. Para asegurarnos de que esto no pase, o
por lo menos poder avisarle al usuario que necesitará realizar una acción específica pa-
ra permitir las ventanas emergentes, es posible hacer uso del siguiente código:
if (HtmlPage.IsPopupWindowAllowed)
{
HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions();
...
...
HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”,
opciones); }
Silverlight 2 y el HTML
303
08_Silverlight.qxp 9/30/09 1:36 PM Page 303
else
{
this.mensaje.Text = “No se permiten ventanas emergentes.”;
}
La propiedad IsPopupWindowAllowed nos permitirá saber si el navegador web del
cliente tiene activado el bloqueo de ventanas emergentes pudiendo, como en el ejem-
plo de la figura siguiente, avisarle al usuario de este impedimento.
Figura 12. Así se muestra al usuario
un mensaje sobre el bloqueo de ventanas emergentes.
Cabe mencionar que además de abrir una ventana emergente dentro de su parámetro
de retorno, HtmlPage.PopupWindow devuelve una referencia del tipo HtmlWindow. Con
esta referencia, es posible modificar el comportamiento de la ventana antes abier-
ta de la misma forma que lo haríamos desde código JavaScript. En el siguiente
código de ejemplo, una vez creada la nueva ventana emergente, si el usuario pre-
siona sobre el segundo botón de la aplicación Silverlight, redirigiremos el conte-
nido de la ventana a otro sitio web.
HtmlWindow window;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (HtmlPage.IsPopupWindowAllowed)
{
8. EL NAVEGADOR Y SU DOMINIO
304
08_Silverlight.qxp 9/30/09 1:36 PM Page 304
HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions();
...
...
...
window = HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”),
“_blank”, opciones); }
else
{
this.mensaje.Text = “No se permiten ventanas emergentes.”;
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
window.Navigate(new Uri(“http://www.bing.com”));
}
Figura 13. Una vez creada la ventana, con el segundo
botón la página es redirigida a un nuevo sitio web.
HtmlWindow
Para extender lo explicado en el apartado anterior, diremos que HtmlWindow re-
presenta una referencia a una ventana del navegador. Ésta puede ser una ventana
emergente o la misma ventana principal donde se ejecuta la aplicación Silverlight.
Además de poder redirigir la página a un nuevo destino, HtmlWindow nos otorga
algunos elementos más con los cuales trabajar.
Silverlight 2 y el HTML
305
08_Silverlight.qxp 9/30/09 1:36 PM Page 305
Por ejemplo, podríamos necesitar requerir información por parte del usuario usando
ventanas específicas del navegador y no creando las nuestras dentro de la aplicación
Silverlight. La ventaja de realizar esto reside en que esos cuadros de diálogo pueden
bloquear el uso de la página hasta que el usuario lo cierre. Al bloquear la interacción
con la página, podemos asegurarnos de que el usuario siga el flujo de nuestra aplica-
ción y no evada ciertas reglas necesarias en nuestro código. El siguiente código otor-
ga la posibilidad de enviar una alerta al usuario en forma de cuadro de diálogo.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
HtmlWindow ventanaPrincipal = HtmlPage.Window;
ventanaPrincipal.Alert(“Esta es una alerta desde Silverlight”);
}
Primero, tomamos la instancia de la ventana del navegador y, luego, mediante el
uso de Alert() (homónimo de JavaScript), disparamos un mensaje al usuario.
Figura 14. Mensaje de alerta desde Silverlight.
Si intentamos acceder a cualquier elemento de la página web o de la aplicación
Silverlight mientras que esta ventana se encuentre activa, notaremos que no es
posible hacerlo, por lo que la única alternativa o curso de acción consiste en pre-
sionar dicho elemento. Es posible extender los mensajes de alerta para pedirle al
usuario confirmaciones sobre ciertas acciones. Por ejemplo, podríamos desplegar
un cuadro de diálogo con dos opciones para que el usuario eligiese y, basados en
su elección, actuar como corresponda.
Figura 15. Cuadro de diálogo con dos opciones seleccionables.
private void Button_Click_3(object sender, RoutedEventArgs e)
{
8. EL NAVEGADOR Y SU DOMINIO
306
08_Silverlight.qxp 9/30/09 1:36 PM Page 306
HtmlWindow ventanaPrincipal = HtmlPage.Window;
if (ventanaPrincipal.Confirm(“¿Está seguro de seguir adelante?”))
{
this.mensaje.Text = “Usted presionó SI”;
}
else
{
this.mensaje.Text = “Usted presionó NO”;
}
}
Si hacemos uso del método Confirm(), podremos mostrar un cuadro de diálogo
con dos opciones seleccionables por parte del usuario, que éste podrá aceptar o
cancelar. Si la respuesta por parte del usuario fuera positiva, Confirm() retornará
True (verdadero) y si no, False (falso). En la Figura 16, se muestran los dos cursos
de acción sobre la base de la selección del usuario.
Figura 16. A la izquierda, el usuario presionó el botón
Aceptar y a la derecha el usuario presionó el botón Cancelar.
Podemos ir todavía un paso más allá y realizar preguntas específicas al usuario,
dejando que éste responda con libertad, introduciendo su respuesta en una caja
de texto del mismo diálogo. Lo hacemos de la siguiente manera:
private void Button_Click_4(object sender, RoutedEventArgs e)
{
Silverlight 2 y el HTML
307
08_Silverlight.qxp 9/30/09 1:36 PM Page 307
HtmlWindow ventanaPrincipal = HtmlPage.Window;
this.mensaje.Text = ventanaPrincipal.Prompt(“¿Le gusta Silverlight?”);
}
En este caso, el cuadro de diálogo se mostrará con el mensaje contenido dentro del
método Prompt() y retornará un tipo de dato de texto que contiene la respuesta
del usuario. En la Figura 17, podemos ver el mensaje que se muestra al usuario,
donde podrá escribir la respuesta, y en la Figura 18 observamos que la respuesta
es escrita dentro de la aplicación Silverlight.
Figura 17. Cuadro de diálogo con una pregunta enviada al cliente.
Figura 18. Lo escrito por el usuario es reflejado en la aplicación Silverlight.
En este mismo capítulo pudimos abrir una nueva ventana emergente haciendo
uso de PopupWindow(), pero también es posible que redirijamos la página web
actual hacia otro destino web sin la necesidad de abrir una ventana nueva que
pueda ser bloqueada por el navegador.
private void Button_Click_5(object sender, RoutedEventArgs e)
{
HtmlWindow ventanaPrincipal = HtmlPage.Window;
8. EL NAVEGADOR Y SU DOMINIO
308
08_Silverlight.qxp 9/30/09 1:36 PM Page 308
ventanaPrincipal.Navigate(new Uri(“http://www.bing.com”));
}
En este caso, estableciendo la página de navegación, en el momento que el usuario pre-
sione el botón de la aplicación Silverlight, el navegador se dirigirá a la nueva página.
Figura 19. A la izquierda, la aplicación Silverlight. A la derecha, el mismo
navegador una vez que el usuario presionó el botón de navegación.
Si fuera necesario, en lugar de lanzar la navegación en la página actual donde re-
side la aplicación Silverlight, podríamos abrir una nueva página, similar a la ge-
nerada por PopupWindow(), pero sin que el navegador bloquee dicha ventana, ya
que ésta no tendría las mismas cualidades. Por ejemplo, no podríamos modificar
los valores de la ventana emergente como el caso de PopupWindow().Utilizando el
atributo _blank, la ventana se visualizará en una nueva ventana.
private void Button_Click_5(object sender, RoutedEventArgs e)
Silverlight 2 y el HTML
309
RRR
El texto de los botones del cuadro de diálogo Confirm() dependerá directamente del idioma del
navegador web que esté usando el usuario, así como también de su versión y su tipo. No se pue-
de, en ningún caso, modificar por código estos valores.
TEXTO EN BOTONES
08_Silverlight.qxp 9/30/09 1:36 PM Page 309
{
HtmlWindow ventanaPrincipal = HtmlPage.Window;
ventanaPrincipal.Navigate(new Uri(“http://www.bing.com”), “_blank”);
}
También podemos, con HtmlWindow, navegar entre marcadores HTML. Los
marcadores HTML son definidos por el tag a y una propiedad que identifi-
que el nombre de este marcador.
a name=”MiMarcador”
Esto permitirá que, en la barra de navegación del navegador web, si especificamos
este marcador, la página nos muestre esa zona.
asp:ScriptManager ID=”ScriptManager1” runat=”server”/asp:ScriptManager
div style=”height:100%;”
asp:Silverlight ID=”Xaml1” runat=”server”
Source=”~/ClientBin/Capitulo8HTML3.xap” MinimumVersion=”2.0.31005.0”
Width=”100%” Height=”100%” /
/div
br /
...
...
br /
a name=”MiMarcador”/a
br /
Marcador HTML
Vemos, en el código anterior, que el marcador se encuentra al final de la página
HTML y nuestra aplicación Silverlight, en la parte superior. Desde Silverlight, po-
dremos navegar hasta ese marcador de la siguiente forma:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
HtmlWindow paginaPrincipal = HtmlPage.Window;
paginaPrincipal.NavigateToBookmark(“MiMarcador”);
}
8. EL NAVEGADOR Y SU DOMINIO
310
08_Silverlight.qxp 9/30/09 1:36 PM Page 310
Notemos la concordancia entre el nombre del marcador HTML y el nombre utiliza-
do en la línea de código Silverlight. Podemos ver el resultado en la siguiente figura.
Figura 20. La página muestra el marcador HTML disparado desde Silverlight.
Podemos extender este ejemplo simple para lograr que, sobre la base de los marcado-
res, podamos cargar diferentes controles Silverlight contenidos en nuestra aplicación.
Al hacer esto, podemos dar mayor facilidad de uso sobre la aplicación. Pensemos en
una aplicación que tenga diferentes estados o páginas internas que se vayan mostran-
do durante la interacción con el usuario.
El usuario podría querer marcar una página específica de la aplicación para luego
acceder directamente a esa parte de la aplicación. Sin embargo, debido a que cada
vez que se carga la aplicación esto se hará desde el inicio, será difícil saber qué par-
te es la que quiere ver el usuario. Pero, aplicando marcadores a la aplicación, es po-
sible conseguir esto. Nuestro primer paso será agregar un nuevo control Silverlight
a la solución. El siguiente paso será modificar el código que inicia la aplicación Sil-
verlight (App.xaml.cs) de la siguiente forma:
private Grid controlPrincipal = new Grid();
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = controlPrincipal;
if (String.IsNullOrEmpty(HtmlPage.Window.CurrentBookmark))
{
controlPrincipal.Children.Add(new Page());
}
Silverlight 2 y el HTML
311
08_Silverlight.qxp 9/30/09 1:36 PM Page 311
else
{
try
{
Type type = this.GetType();
Assembly assembly = type.Assembly;
UserControl controlDestino =
(UserControl)assembly.CreateInstance(
HtmlPage.Window.CurrentBookmark);
controlPrincipal.Children.Add(controlDestino);
}
catch
{
controlPrincipal.Children.Add(new Page());
}
}
}
public static void Navegar(UserControl controlDestino)
{
HtmlPage.Window.NavigateToBookmark(controlDestino.GetType().FullName);
}
El código utiliza mecanismos de reflexión sobre los componentes para determinar qué
control instanciar, basándose en el nombre contenido en el marcador del navegador
web. Las siguientes líneas reconocen este nombre, buscan el control que corresponda,
generando una instancia, y sobrescriben el aspecto visual original del control.
Assembly assembly = type.Assembly;
UserControl controlDestino =
(UserControl)assembly.CreateInstance(
HtmlPage.Window.CurrentBookmark);
controlPrincipal.Children.Add(controlDestino);
Además, hemos agregado un método estático que se encargará de hacer navegar
la página web al marcador designado, utilizando como nombre del marcador el
nombre de instancia del control. Esto nos permitirá realizar el siguiente código
desde cualquier otro control Silverlight en el proyecto.
8. EL NAVEGADOR Y SU DOMINIO
312
08_Silverlight.qxp 9/30/09 1:36 PM Page 312
private void Button_Click(object sender, RoutedEventArgs e)
{
App.Navegar(new Pagina2());
}
En la Figura 21 y en la Figura 22, podemos ver ejemplos con el resultado de aplicar
este comportamiento a un proyecto.
Figura 21. La aplicación navegó hasta
el segundo marcador, mostrando un contenido nuevo.
Figura 22. Al presionar sobre el botón contenido
en el control anterior, éste navegará a la página principal.
Silverlight 2 y el HTML
313
08_Silverlight.qxp 9/30/09 1:36 PM Page 313
Prestemos atención al marcador que se genera por la aplicación Silverlight. La
primera parte antes del punto hace referencia al nombre del ensamblado. Este
nombre podemos obtenerlo desde las propiedades del proyecto.
#Capitulo8HTML3.Pagina2
La segunda parte, después del punto, se refiere al nombre del control de usuario o
clase que manejará ese control. Deberemos tener en cuenta esto para poder gene-
rar, de manera correcta, la instancia del control que se va a visualizar.
Figura 23. Propiedades del proyecto Silverlight,
donde encontramos el nombre del ensamblado.
Cookies
Las cookies son archivos de texto que se alojan en el equipo del cliente. Casi siem-
pre, son usados para dejar información del usuario para luego reutilizarla según la
necesidad. Los casos más comunes de uso de cookies los podemos encontrar en aque-
llos sitios web en los que, al ingresar, nos preguntan si deseamos que nos recuerden,
por ejemplo, nuestro nombre de usuario y contraseña para validar nuestra entidad,
para que no debamos volver a colocarlos la próxima vez que ingresemos. Estos sitios
dejan un archivo de texto con valores y fecha de expiración en nuestra computado-
ra, que leerán posteriormente para así recuperar eso que habían almacenado.
Desde una aplicación Silverlight es posible, también, leer cookies que hayan sido cre-
adas por el sitio web donde ésta trabaja o crear estos elementos para el mismo sitio web.
No debemos comparar las cookies con la característica de almacenamiento aislado
provista por Silverlight. Si bien la capacidad de las cookies para almacenar información
8. EL NAVEGADOR Y SU DOMINIO
314
08_Silverlight.qxp 9/30/09 1:36 PM Page 314
es limitada, estos elementos se guardan en el equipo del cliente y pueden ser compar-
tidos con otros ambientes de desarrollo. Estas cookies podrían ser manipuladas desde
una aplicación ASP.net, como por JavaScript. Por este motivo, las cookies pueden con-
vertirse en un buen canal de comunicación entre las distintas plataformas.
En el siguiente ejemplo, crearemos una cookie desde ASP.net, que leeremos y mo-
dificaremos desde Silverlight. Lo primero será crear la estructura y el código ASP.net.
asp:Button ID=”Button1” runat=”server” Text=”Crear Cookie”
onclick=”Button1_Click” /
nbsp;asp:Button ID=”Button2” runat=”server” Text=”Ver Cookie”
onclick=”Button2_Click” /
br /
asp:Label ID=”mensaje” runat=”server” Text=”Valor del Cookie:” Font-
Names=”Arial”/asp:Label
Aquí creamos dos botones, uno para crear la cookie y el otro para leerla. Los valores
serán desplegados en el campo de texto que se encuentra declarado al final de las lí-
neas anteriores. Para crear cookies desde ASP.net, escribiremos el siguiente código:
protected void Button1_Click(object sender, EventArgs e)
{
Response.Cookies.Add(new HttpCookie(“CookieSilver”, “1234”));
}
protected void Button2_Click(object sender, EventArgs e)
{
this.mensaje.Text = “Valor del Cookie: “ +
Request.Cookies[“CookieSilver”].Value.ToString();
}
El primer método crea una cookie llamada CookieSilver, que contiene el valor 1234.
El segundo método lee y escribe el contenido de la cookie en el campo de texto. Una
vez terminado este paso, podremos tomar esta cookie desde Silverlight. En el evento
de presionado del botón, agregaremos el código de lectura y recolección de la cookie.
private void Button_Click(object sender, RoutedEventArgs e)
{
string[] cookies = HtmlPage.Document.Cookies.Split(‘;’);
Silverlight 2 y el HTML
315
08_Silverlight.qxp 9/30/09 1:36 PM Page 315
foreach (string cookie in cookies)
{
string[] valores = cookie.Split(‘=’);
if (valores.Length == 2)
{
if (valores[0].ToString() == “CookieSilver”)
{
this.mensaje.Text = “Valor del Cookie: “ +
valores[1];
break;
}
}
}
}
Hemos recolectado toda la información de las cookies disponibles mediante la línea:
string[] cookies = HtmlPage.Document.Cookies.Split(‘;’);
Debido a que podría haber más de una cookie, cada una de éstas se separarán me-
diante el identificador de ; (punto y coma). Además, las cookies serán almacena-
das con la estructura [Nombre]=[Valor], por lo que, delante del signo igual en-
contraremos el nombre de la cookie y seguido, el valor almacenado. Al ejecutar el
código, obtendremos algo similar a lo siguiente.
Figura 24. La cookie fue recolectada por la aplicación Silverlight.
8. EL NAVEGADOR Y SU DOMINIO
316
08_Silverlight.qxp 9/30/09 1:36 PM Page 316
Por supuesto, también es posible crear o sobrescribir una cookie ya existente desde
una aplicación Silverlight. Para esto, es necesario utilizar un modelo diferente que
no incluye el uso de HtmlPage.Document.Cookies. En este caso, usaremos SetProperty,
modificando el valor de la propiedad cookie del navegador.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
DateTime fechaExspiracion = DateTime.Now + TimeSpan.FromDays(7);
string nuevoCookie = “CookieSilver=Nuevo Valor;expires=”
+ fechaExspiracion.ToString(“R”);
HtmlPage.Document.SetProperty(“cookie”, nuevoCookie);
}
Notemos que, además del valor de la cookie, también es posible especificar una
fecha de expiración. Esto quiere decir que, si agregamos una fecha a la cookie,
ésta se mantendrá disponible hasta esa fecha. En caso de no especificar una fecha,
la cookie se eliminará en el momento en el que abandonemos la página que la
creó. En la Figura 25, podemos observar que el valor de la cookie modificada des-
de la aplicación Silverlight también es reconocido desde ASP.net.
Figura 25. La nueva cookie es reconocida por ASP.net.
Modificar CSS
Las hojas de estilo, también conocidas como CSS, pueden ser alteradas desde la
aplicación Silverlight. Debido a que tenemos acceso al modelo de objetos de la
Silverlight 2 y el HTML
317
08_Silverlight.qxp 9/30/09 1:36 PM Page 317
página HTML, cualquier elemento presente en ésta podría ser cambiado desde
nuestra aplicación. En el caso del uso de estilos, puede resultar de utilidad cuan-
do necesitemos informar al usuario de algún acontecimiento modificando la ti-
pografía o los colores del elemento. A continuación, veamos dos estilos creados
en la página donde se ejecutará nuestra aplicación:
style type=”text/css”
.estilo1
{
font-family: Arial;
font-size: larger;
color: Blue;
}
.estilo2
{
font-family: Verdana;
font-size: smaller;
color: Green;
}
/style
Estos estilos presentan una tipografía específica para cada uno, así como un tama-
ño de letra y un color especial. Apliquemos el primer estilo a un texto en HTML.
span class=”estilo1” id=”texto”Texto con estilos/span
En este caso, mediante el uso de class, asignamos el primer estilo a la frase Texto con
estilos. Podemos ver el resultado en la siguiente imagen:
8. EL NAVEGADOR Y SU DOMINIO
318
_`
El desarrollo web ha evolucionado tanto a lo largo de los años que la aplicación de los formatos vi-
suales a textos, imágenes, colores de fondo, posición de distintos elementos y otros aspector pa-
só de ser declarado con etiquetas HTML al uso total de las hojas de estilo. Al momento de diseñar
nuestros sitios web, es una buena práctica aplicar esta técnica por sobre el uso de tags HTML.
DE HTML A CSS
08_Silverlight.qxp 9/30/09 1:36 PM Page 318
Figura 26. El texto se muestra con las características del primer estilo creado.
Si tomamos el elemento desde la página web desde su HTML, mediante el identifica-
dor del elemento, estaremos en posición de modificar el estilo por otro de la lista de es-
tilos creados con anterioridad, una vez presionado el botón en la aplicación Silverlight.
private void Button_Click(object sender, RoutedEventArgs e)
{
HtmlPage.Document.GetElementById(“texto”).CssClass = “estilo2”;
}
Figura 27. El formato de la frase cambió de acuerdo con el segundo estilo declarado.
Silverlight 2 y el HTML
319
08_Silverlight.qxp 9/30/09 1:36 PM Page 319
Otra posibilidad, si no contamos con una estructura de estilos predefinida, es la de
modificar los valores de los estilos en el elemento HTML, utilizando el nombre de
la propiedad que hace referencia al estilo que queramos modificar.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
HtmlElement etiqueta = HtmlPage.Document.GetElementById(“texto2”);
etiqueta.SetStyleAttribute(“border”, “dashed 3px black”);
etiqueta.SetStyleAttribute(“color”, “red”);
}
Por cada estilo que deseemos aplicar, necesitamos realizar una llamada al método
SetStyleAttribute(), especificando el nombre del estilo y su valor. Observemos, en
la siguiente figura, cómo se visualiza el elemento HTML antes de aplicar un estilo
y cómo queda luego su posterior transformación.
Figura 28. A izquierda, vemos una etiqueta sin estilo alguno.
Al procesar el código Silverlight, éste aplica los estilos especificados.
SILVERLIGHT 2 Y JAVASCRIPT
Así como hemos podido interactuar con el HTML contenedor de la aplicación Silver-
light, también es posible hacerlo con el código JavaScript que se ejecuta en el navega-
dor. Esta característica puede resultar muy valiosa si tenemos en cuenta el uso actual
que se le da a la Web y todas las tecnologías involucradas. Por ejemplo, la implemen-
8. EL NAVEGADOR Y SU DOMINIO
320
08_Silverlight.qxp 9/30/09 1:36 PM Page 320
tación de A.J.A.X., tecnología que le da vida a la Web 2.0, se nutre profundamente de
JavaScript, por lo que tener control sobre este lenguaje, desde Silverlight y hacia él, pue-
de potenciar mucho más las posibilidades de desarrollo de aplicaciones web. Como
primera instancia, asociaremos un evento JavaScript a un elemento HTML que, cuan-
do se ejecute, será capturado por la aplicación Silverlight para manejar este proceso.
private void Button_Click(object sender, RoutedEventArgs e)
{
HtmlElement elemento = HtmlPage.Document.GetElementById(“contenedor”);
elemento.AttachEvent(“onclick”, BotonCliente_Click);
}
private void BotonCliente_Click(object sender, HtmlEventArgs e)
{
...
...
Las líneas anteriores toman un elemento HTML, para este caso, un botón, y adjuntan,
al evento OnClick de JavaScript para ese botón, un manejador que se encontrará tra-
bajando en la aplicación Silverlight. Cuando el usuario presione sobre el botón HTML,
el método BotonCliente_Click se disparará y podremos ejecutar nuestro código.
Figura 29. El evento fue disparado desde el cliente.
Una vez disparado, podríamos ejecutar la lógica de la aplicación como para llamar a
servicios web que retornen información, o construir nuevo HTML para el usuario.
Esto puede convertirse en una herramienta poderosa si quisiéramos encapsular lógi-
Silverlight 2 y JavaScript
321
08_Silverlight.qxp 9/30/09 1:36 PM Page 321
ca de código dentro de un lenguaje común como C# o cualquiera que utilicemos con
Microsoft .Net. Pensemos que, muchas veces, la depuración de código JavaScript
puede resultar compleja al extremo, incluso lenta, a medida que este código sube en
dificultad. Conectarse a servicios web podría requerir de cientos de líneas de código,
incluyendo el análisis del XML retornado por éste, así como el manejo de errores
de conexión y demás. Por otro lado, podríamos llevar esta lógica a un componente
Silverlight sin interfaz visual que se encargue de capturar cada uno de los eventos pro-
ducidos en JavaScript por el cliente y manejarlos como si se tratase de una aplicación
creada con Microsoft .Net. Esto podría ahorrarnos tiempo y esfuerzo, así como dar-
nos la posibilidad de realizar mantenimiento futuro al código de forma mucho más
eficiente. Los controles HTML cuentan con una serie de eventos a los que podemos
subscribir los eventos Silverlight. Éstos se listan a continuación:
• onchange: este evento se disparará cuando el control asociado sufra una modifica-
ción. En el caso de cajas de texto, si el usuario modifica su contenido; y en listas
desplegables, si otro elemento de la lista es seleccionado. En la mayoría de los ca-
sos, el control deberá perder el foco para que el evento aplique.
• onclick: se dispara cuando el usuario presiona el elemento con el mouse.
• onmouseover: éste se disparará cuando el mouse pase por arriba del elemento. Jun-
to con los valores pasados por argumento, se podrán encontrar las coordenadas
por las cuales el mouse se mueve.
• onmouseout: en el momento en el que el mouse deje la superficie del control
HTML, este evento nos avisará.
• onkeydown: si el usuario presiona una tecla cuando está dentro de un elemen-
to, por lo general representado por una caja de texto, podremos saber qué tecla
es la que está presionando.
• onkeyup: si el usuario deja de presionar una tecla del teclado, el evento nos avisará.
• onkeypress: si el usuario presionó y soltó una tecla, este evento se disparará.
• onfocus: este evento será ejecutado cada vez que un control tome el foco. Esto es,
que el cursor de escritura esté sobre él o si el usuario hubiera presionado con el
botón del mouse sobre el control para conseguir el foco.
• onblur: cada vez que un control pierda el foco, se disparará este evento.
• onload: se dispara cuando la página termina de cargar todo su contenido.
• onunload: cada vez que la página sea destruida, el evento nos avisará. Este even-
to asume que la página será descargada de la memoria del navegador cuando
naveguemos a otra página o cuando presionemos un vínculo que haga que el
contenido de la página se recargue.
Por consiguiente, podríamos subscribirnos a cualquiera de los eventos antes lista-
dos. Debemos tener en cuenta que algunos eventos sólo son soportados por ciertos
navegadores, por lo que deberíamos utilizarlos con cuidado.
8. EL NAVEGADOR Y SU DOMINIO
322
08_Silverlight.qxp 9/30/09 1:36 PM Page 322
Llamar funciones
Como dijimos, también es posible llamar a funciones JavaScript desde código Sil-
verlight. Esto nos será de gran utilidad en casos en los que tengamos sitios web ya
implementados, con lógica incluida en líneas de código JavaScript, y queramos ex-
tender esa funcionalidad desde Silverlight. Lo primero que necesitamos es algo de
código JavaScript para poder utilizarlo desde Silverlight.
script language=”javascript” type=”text/javascript”
function MostrarMensaje(mensaje) {
alert(mensaje);
}
/script
En este caso, sólo mostraremos un mensaje emergente, pasando un parámetro que
representa el texto por mostrar. Desde Silverlight, usaremos el objeto HtmlPage y
HtmlWindow para capturar el código JavaScript y ejecutarlo.
HtmlPage.Window.Invoke(“MostrarMensaje”, “Mensaje desde Silverlight”);
El primer parámetro del método Invoke() especifica el nombre de la función JavaScript
por ejecutar. El segundo y todos los siguientes representan cada uno de los parámetros
que la función JavaScript pudiera necesitar. Así, si tenemos más de un parámetro que
pasar a la función JavaScript, podremos colocarlos separados por comas. Como vemos
en la siguiente figura, el mensaje de alerta es ejecutado en forma correcta.
Figura 30. Al presionar el botón,
Silverlight llama y ejecuta la función JavaScript.
También es posible utilizar otra forma de referenciar y de ejecutar código JavaScript.
La siguiente línea hará el mismo trabajo que lo planteado en las líneas anteriores:
ScriptObject script =
(ScriptObject)HtmlPage.Window.GetProperty(“MostrarMensaje”);
script.InvokeSelf(“Mensaje desde Silverlight. Nueva forma”);
Silverlight 2 y JavaScript
323
08_Silverlight.qxp 9/30/09 1:36 PM Page 323
En este caso, tomamos como una propiedad de la ventana actual el nombre de la
función JavaScript y transformamos el resultado a un tipo ScriptObject, que alber-
gará la función y su funcionalidad. En la Figura 31, observamos que el mensaje se
despliega de la misma forma que en el caso anterior.
Figura 31. Utilizando otra forma
de ejecutar código, obtenemos similares resultados.
Objetos Silverlight para JavaScript
Silverlight también puede exponer métodos y funciones internas, como objetos
JavaScript. En los apartados anteriores trabajamos con eventos y los ejecutamos de un
lado y del otro, haciendo que Silverlight fuera el centro de atención, ya que éste se en-
cargaba de la ejecución de funciones JavaScript, así como de la captura de eventos des-
de el navegador cliente. Por otro lado, es posible dar mayor protagonismo a JavaScript
haciendo que Silverlight exponga sus métodos y funciones para que sean consumidos
desde el código cliente. Esta posibilidad nos acercaría más al concepto de usar Silverlight
como un proveedor de funcionalidad compleja en casos donde la misma implemen-
tación por parte de JavaScript acarrearía mucho más esfuerzo. Para lograr esto, es ne-
cesario decorar, con un atributo, la clase Silverlight que se expondrá hacia JavaScript
y, con un segundo atributo, cada método o función que necesitemos exponer.
[ScriptableType()]
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject(“Silver”, this);
}
[ScriptableMember()]
public void MostrarMensaje(string mensaje)
{
this.txtMensaje.Text = mensaje;
}
}
8. EL NAVEGADOR Y SU DOMINIO
324
08_Silverlight.qxp 9/30/09 1:36 PM Page 324
La primera línea, ScriptableType(), marca la clase como un tipo que podrá ser con-
sumido desde JavaScript. La siguiente línea:
HtmlPage.RegisterScriptableObject(“Silver”, this);
La línea anterior se encarga de registrar el código JavaScript que servirá de interfaz
entre Silverlight y el código JavaScript que consuma esta funcionalidad. Para esto,
es necesario especificar un nombre de objeto y la clase que se usará como punto de
entrada del script. Por su parte, la línea ScriptableMember() hace referencia a los mé-
todos y funciones que podrán ejecutarse desde JavaScript. Podremos tener tantos
ScriptableMember() como funciones o métodos queramos exponer. Una vez expuesta
esta información, podremos consumirla de la siguiente forma:
script type=”text/javascript”
function Mostrar()
{
var micontrol = document.getElementById(“AplicacionSilverlight”);
micontrol.content.Silver.MostrarMensaje(“Mensaje desde JavaScript.”);
}
/script
El código JavaScript anterior captura el objeto Silverlight embebido en la pági-
na web. Este control se identifica mediante el uso del atributo ID dentro de su
propia declaración, como podemos ver en el siguiente código:
object id=”AplicacionSilverlight” data=”data:application/x-silverlight-2,”
type=”application/x-silverlight-2” width=”400” height=”200”
param name=”source” value=”ClientBin/Capitulo8JavaScript2.xap”/
param name=”onerror” value=”onSilverlightError” /
...
...
Luego, se utiliza la referencia al objeto creado desde Silverlight, llamado Silver, el
cual contiene la función MostrarMensaje(). La función JavaScript Mostrar() es lla-
mada para este caso desde el evento onclick de un botón HTML.
input type=”button” value=”Mostrar mensaje” onclick=”Mostrar();” /
Silverlight 2 y JavaScript
325
08_Silverlight.qxp 9/30/09 1:36 PM Page 325
Figura 32. Al presionar el botón, el mensaje
enviado desde JavaScript se muestra en Silverlight.
También es posible crear objetos más complejos para que sean consumidos desde
JavaScript. Podemos exponer una clase por completo y que ésta pueda ser instan-
ciada y consumida desde el código JavaScript. Veamos la siguiente clase:
[ScriptableType()]
public class Sumar2
{
[ScriptableMember()]
public long Sumar2Numeros(long valor1, long valor2)
{
return valor1 + valor2;
}
}
Esta clase posee una función que retornará la suma de los dos parámetros enviados.
Si registramos esta clase como código JavaScript del cual se pueda crear una ins-
tancia, podremos acceder a ésta como si se tratase de código JavaScript.
HtmlPage.RegisterCreateableType(“Sumar2”, typeof(Sumar2));
En este caso, el objeto por construir desde JavaScript se llamará Sumar2 y tendrá
disponibles todos los métodos de la clase creada antes. Para obtener una instan-
cia de este objeto en JavaScript, deberemos hacer lo siguiente:
8. EL NAVEGADOR Y SU DOMINIO
326
08_Silverlight.qxp 9/30/09 1:36 PM Page 326
function Sumar() {
var MiControl = document.getElementById(“AplicacionSilverlight”);
var sumar2 = MiControl.content.services.createObject(“Sumar2”);
alert(sumar2.Sumar2Numeros(10, 20));
}
Figura 33. Al presionar el botón para sumar, obtenemos el resultado correcto.
En la siguiente figura, podemos ver que el objeto creado, si bien es consumido
desde JavaScript, en el momento en que se procesa es ejecutado en Silverlight. Esto
significa que no se está creando código JavaScript que simule la funcionalidad crea-
da en Silverlight, sino que se llama a la función en Silverlight previamente definida.
Figura 34. La ejecución desde JavaScript dispara el código en Silverlight.
Silverlight 2 y JavaScript
327
… RESUMEN
En este capítulo hemos visto que Silverlight tiene la capacidad de salir fuera de su marco tra-
dicional de ejecución e interactuar con el entorno dentro del navegador, tanto con el código
HTML como con el código JavaScript. Este último es posible ejecutarlo, manipularlo y consu-
mirlo para generar mayor interacción con nuestro sitio web y con el usuario. Gracias a esto,
Silverlight no sólo otorga funcionalidad dentro de su modelo de ejecución, sino que también
extiende las funcionalidades circundantes dentro del navegador web.
08_Silverlight.qxp 9/30/09 1:36 PM Page 327
328

PREGUNTAS TEÓRICAS
1 ¿Qué objeto debemos usar desde Silverlight 2
para obtener información de la página
HTML contenedora de la aplicación?
2 ¿Es posible modificar los valores de los
objetos creados en el código HTML desde
Silverlight 2?
3 ¿Cuándo se usa el método GetElementById
desde Silverlight 2?
4 ¿Cómo podemos ejecutar el envío de un for-
mulario web desde Silverlight 2?
5 ¿Cómo podemos lanzar una nueva ventana
del navegador desde Silverlight 2?
6 ¿Qué es una cookie?
7 ¿Cómo leemos y escribimos cookies desde
Silverlight 2?
8 ¿Cómo podemos ejecutar código JavaScript
desde Silverlight 2?
9 ¿Qué atributo decorativo necesitamos utili-
zar para que el código Silverlight pueda ser
ejecutado desde JavaScript?
10¿Qué eventos JavaScript se disparan sólo
por medio de la acción del usuario? Nom-
bre algunos de ellos.
ACTIVIDADES
EJERCICIOS PRÁCTICOS
1 Visite el sitio de CodePlex (www.codeplex.
com/IronPython), para informarse de có-
mo implementar tecnologías tales como
IronPython y Silverlight 2.
2 Para conocer más sobre el uso de reflexión
sobre Microsoft .Net, ingrese en http://
msdn.microsoft.com/es-es/.
3 Modifique el ejemplo de navegación por
marcadores para incluir un nuevo control.
4 Con el nuevo control creado en el ejercicio
anterior, utilice cookies para dirigir al
usuario a la página que estaba viendo, en
la aplicación Silverlight, antes de cerrar la
ventana del navegador.
5 Pruebe crear una aplicación Silverlight que
se visualice en modo de pantalla completa.
08_Silverlight.qxp 9/30/09 1:36 PM Page 328
Silverlight fuera
de Windows
Proyecto Moonlight 330
Sistemas operativos 330
Versiones de Moonlight 331
Herramientas de desarrollo 331
Problemas conocidos 333
Apéndice A
Silverlight es una tecnología provista
y mantenida por Microsoft. Si bien esta
compañía centra su desarrollo
en los sistemas operativos con mayor
uso en el mercado de computadoras
de escritorio de la actualidad, como
OS X de Apple y Windows, la comunidad
también hace su trabajo, creando
soporte para sistemas operativos
como Linux y Unix.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 329
PROYECTO MOONLIGHT
Moonlight es un proyecto creado por la comunidad de desarrolladores y patro-
cinado por la compañía Novell. El objetivo de Moonlight es el de poder crear y
ejecutar aplicaciones Silverlight bajo sistemas operativos con base Linux y Unix.
De esta forma, es posible llevar el uso de esta tecnología a la mayor gama de usua-
rios, sin importar su sistema operativo e, incluso, su navegador. Teniendo en
cuenta que de manera nativa Silverlight es soportado por Opera, Internet Ex-
plorer y Firefox bajo Windows y OS X de Apple, con Moonlight se amplía el
horizonte al ejecutar Silverlight en Linux con Firefox.
Figura 1. En la dirección www.mono-project.com/Moonlight
encontramos el sitio web del proyecto Moonlight.
Sistemas operativos
Moonlight fue diseñado para soportar diferentes sistemas operativos Linux, tanto para
arquitecturas x86 de 32 Bits como x86-64 para 64 Bits. En la Tabla 1, podemos ver la
lista de sistemas operativos y versiones de navegadores web soportados en cada caso.
ARQUITECTURA SISTEMA OPERATIVO FIREFOX 2.0 FIREFOX 3.0
x86 (32 Bits) SUSE Linux Enterprise Desktop 10 Sí Sí
openSUSE 11.0 Sí Sí
openSUSE 11.1 Sí Sí
Ubuntu 8.04 Sí Sí
Fedora Core 9 Sí Sí
x86-64 (64 bits) SUSE Linux Enterprise Desktop 10 Sí Sí
openSUSE 11.0 No Sí
Tabla 1. Sistemas operativos y navegadores web soportados por Moonlight.
APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS
330
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 330
En cuanto a requerimientos, para ejecutar una aplicación Silverlight desde Firefox, de-
beremos contar con 128 MB de memoria RAM, en cualquiera de las arquitecturas.
Versiones de Moonlight
En la actualidad, Moonlight cuenta con soporte total para Silverlight 1.0. La nueva
versión con soporte para Silverlight 2.0 continúa en desarrollo y tiene fecha de sali-
da para septiembre de 2009. Esto puede ser un punto en contra para Moonlight y
los usuarios de Linux, porque Microsoft ya cuenta con la versión 3 de Silverlight li-
berada. Tengamos en cuenta que la capacidad de desarrollo y conocimiento sobre la
tecnología Silverlight nace desde Microsoft, por lo que es natural pensar y esperar
que la empresa esté un paso adelante en la entrega de nuevas versiones y de nuevas
funcionalidades para sus productos, mientras que la comunidad debe esperar la sali-
da de estos productos y tecnologías, analizarlos, estudiarlos, para luego poder imple-
mentarlos. Este ciclo continuo de nuevas versiones y constante aprendizaje por parte
de la comunidad acarrea este tipo de conflictos con las versiones, dejando a muchos
usuarios desactualizados y desatendidos. De cualquier manera, la nueva versión de
Moonlight pretende mostrar significantes cambios, como la inclusión de Deep
Zoom, Microsoft Media Pack 2.0 para manejo de video y sonido, la posibilidad
de utilizar los controles y componentes propuestos por Microsoft para Silverlight,
entre otras características que lo acercan mucho más a su versión para Windows.
Herramientas de desarrollo
Si bien el comportamiento de la librería de clases provista por Microsoft es el mis-
mo usado por Moonlight, los creadores de éste no recomiendan el uso de Visual
Studio 2008 para la creación de aplicaciones Silverlight específicas para Linux. Es-
to se debe a que, al estar Moonlight en continuo desarrollo, aún presenta ciertos
errores, en especial para Silverlight 2, que podrían causar un comportamiento no
esperado dentro de sistemas operativos basados en Linux. En todo caso, si qui-
siéramos desarrollar directamente bajo Linux, los creadores recomiendan el uso
de la herramienta de desarrollo llamada MonoDevelop.
Proyecto Moonlight
331
Si queremos iniciarnos en el desarrollo de Moonlight o, simplemente, visualizar aplicaciones cre-
adas con esta tecnología en Linux, es posible descargar el plugin de Moonlight de la siguiente
página web: www.go-mono.com/moonlight. Allí también podemos encontrar instrucciones de
instalación y el historial de cambios de la aplicación.
DESCARGAR MOONLIGHT
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 331
Figura 2. MonoDevelop, una herramienta gratuita
creada por la comunidad desarrolladora de Mono y Moonlight.
MonoDevelop es, también, una herramienta de uso libre y gratuito para el desarro-
llo con Mono, lo que quiere decir que nos proveerá herramientas no sólo para el de-
sarrollo de aplicaciones Silverlight, sino que podremos crear aplicaciones web y de
escritorio para Linux utilizando Microsoft .Net Framework como modelo base y C#
como lenguaje de desarrollo. A la fecha, MonoDevelop se encuentra en su versión 2,
y, como en toda comunidad de código abierto, es posible participar en su mejora.
Como ya dijimos, Moonlight es un proyecto de la comunidad para la comunidad. És-
te es libre y de código abierto. Por tal motivo, si deseamos colaborar en su mejora con-
tamos con la posibilidad de hacerlo. En el sitio web de Moonlight, podemos encontrar
las direcciones de los servidores SVN (Subversion o repositorio de versiones), que nos
darán acceso al código y a cada una de las versiones históricas de estos archivos.
Si no contamos con un cliente SVN o herramienta similar, existen excelentes alterna-
tivas gratuitas que hallaremos en Internet. Por ejemplo, TortoiseSVN, una de las re-
comendadas y usadas ampliamente en el desarrollo de software. TortoiseSVN cuenta
con versiones para arquitecturas de 32 y 64 bits. No sólo es útil para este caso especi-
fico, ya que podemos sacarle provecho al incluirlo en nuestros desarrollos de software,
y al utilizarlo con sitios web que brindan servicios gratuitos de almacenamiento para
APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS
332
Es importante recordar que MonoDevelop es una herramienta de uso libre y gratuito, con la
que podremos llevar nuestras aplicaciones .Net a la plataforma Linux, rompiendo la barrera
tradicional entre sistemas operativos. Podemos descargar MonoDevelop desde la siguiente
dirección: http://monodevelop.com.
MONODEVELOP
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 332
desarrollo de productos de software, como Google Code (http://code.google.com/
hosting/) o Microsoft CodePlex (www.codeplex.com), sitio que podemos utilizar
como repositorio de código fuente. Además, es posible encontrar grandes cantidades
de código de ejemplo para utilizar en nuestros proyectos.
Figura 3. TortoiseSVN es una poderosa herramienta
para el manejo de archivos históricos en el desarrollo de software.
Figura 4. Google Code es un repositorio de código para alojar
el código de nuestro proyecto y poder trabajar de forma colaborativa.
Problemas conocidos
Debido a que Moonlight se basa en el modelo de trabajo propuesto por Mono, las
limitaciones de este último son traspasadas también a Moonlight y a la ejecución
de Silverlight. Además, por estar un paso atrás en el soporte de las versiones ofi-
ciales de Silverlight, otros problemas relacionados con la funcionalidad misma de
Proyecto Moonlight
333
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 333
Silverlight aparecen en Moonlight. Una de las destacadas y heredadas del modelo de
trabajo Mono que sustenta Moonlight es la falta de implementación de LinQ en su
totalidad, por lo que es recomendable no utilizar este tipo de consultas integradas
dentro del código que realicemos bajo Linux. Por otro lado, el modelo de trabajo
Mono está enfocado para soportar y simular funcionalidad presentada en Microsoft
.Net Framework 2.0. Como en el transcurso del libro trabajamos con funcionalida-
des presentes en Microsoft .Net Framework 3.0 y 3.5, puede que la mayoría del có-
digo presentado deba ser adaptado a la versión 2.0 de Microsoft .Net Framework.
De cualquier manera, no todo está rodeado de malas noticias, ya que la comunidad
detrás de Moonlight es una comunidad activa y en constante crecimiento Ésta hará
de Moonlight un sistema cada vez más robusto y funcional con el correr del tiempo,
a medida que se sumen más personas con espíritu colaborativo que quieran apoyar
el desarrollo de mejora del proyecto.
Figura 5. En el sitio web de Moonlight, se listan algunos sitios
con los que se prueban las diferentes versiones de esta herramienta
y su resultado al ejecutar aplicaciones Silverlight.
Como vimos, Moonlight es un gran proyecto propuesto por la comunidad desa-
rrolladora de código libre y abierto y, si bien puede estar desfasado en relación con
las nuevas versiones de Silverlight producidas por Microsoft, no deja de ser un com-
ponente que evoluciona día a día y que permite, con facilidad, mover la tecnología
Silverlight a ambientes donde no llegaría por sí sola. No dudemos en apoyar este ti-
po de emprendimientos y desarrollos que nos permiten obtener mayor cantidad y
mejor calidad de productos de software.
APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS
334
09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 334
Silverlight 3,
la nueva
generación
Silverlight 3 336
Nuevos controles 336
Efectos en tres dimensiones 337
Uso de Pixel Shader 338
Fuera del navegador 339
Apéndice B
En el momento en que se edita este libro,
Microsoft saca a la luz la versión 3
de Silverlight. Por eso, en este apartado,
tocaremos los temas más importantes
que diferencian a Silverlight 2
de Silverlight 3, para así poder acoplarnos
con facilidad a esta reciente tecnología.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 335
SILVERLIGHT 3
Silverlight 3 viene con grandes mejoras para el desarrollador, algo que también se tra-
duce en progresos para el usuario. Mejor uso del hardware del equipo cliente, imple-
mentación de funcionalidades de tres dimensiones, mayor soporte para formatos de
video y sonido, y la posibilidad de ejecutar la aplicación fuera del navegador son sólo
algunas de los nuevos adelantos. Curiosamente, el tamaño del plugin para descargar
por los navegadores es apenas menor que el de la versión anterior, lo que también nos
dice que el código de éste se ha optimizado de manera sustancial al incorporar mayor
funcionalidad con menos líneas de código por parte de su motor de ejecución.
Nuevos controles
En esta entrega de Silverlight 3, fueron agregados nuevos controles. Muchos de
éstos son para satisfacer necesidades puntuales sobre carencias anteriores. A la hora
de desarrollar aplicaciones, es común encontrarse con necesidades básicas sobre el
comportamiento de los controles, por lo que, si la tecnología no trae la solución
incluida en ella, es necesario construir líneas de código con funcionalidad para
subsanar este problema. Por este motivo, es común que Microsoft, por cada en-
trega de nuevas tecnologías, incorpore mayores controles de aquellos que recono-
ce como necesarios por parte de los desarrolladores. Uno de estos controles es el
campo de texto con la funcionalidad de autocompletar. Pasándole una fuente
de datos cualquiera, es posible que este control muestre una lista desplegable con
los elementos que coincidan con lo introducido por el usuario.
input:AutoCompleteBox x:Name=”autoCompletar” IsTextCompletionEnabled=”True”
Width=”200” Height=”30”
/input:AutoCompleteBox
Si tenemos cualquier fuente de datos, incluso servicios web o WCF de donde ob-
tener esta información, este control nos mostrará los datos de cómo hacerlo.
APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN
336
Para mantenerse actualizado sobre las nuevas funcionalidades incluidas en Silverlight 3, po-
demos ver los videos tutoriales en el sitio web oficial de Silverlight. Debemos ingresar en el
siguiente sitio para visualizar estos videos: http://silverlight.net/learn/. Vale aclarar que los
videos se encuentran en inglés.
ACTUALIZARSE
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 336
Figura 1. Una lista desplegable
basada en la selección del usuario.
Otros controles como el TreeView (árbol jerárquico), ValidationSummary (resumen
de validaciones) o DataPager (paginador) son también parte del nuevo abanico de
controles y componentes disponibles en esta versión.
Efectos en tres dimensiones
Silverlight 3 adiciona la característica de manipular objetos bidimensionales en un es-
pacio tridimensional. Si bien no incluye, aún, el manejo de objetos tridimensionales
de forma nativa, sí es posible simular este comportamiento mediante un nuevo con-
junto de transformaciones. Estas transformaciones son llamadas proyecciones, y tra-
bajan manipulando el elemento dentro del espacio XYZ según los grados de rotación.
Image Source=”bosque_pokemon.jpg” Width=”400” Height=”250”
Image.Projection
PlaneProjection RotationX=”50”
RotationY=”30”
RotationZ=”35”
/PlaneProjection
/Image.Projection
/Image
Veamos, en la Figura 2 de la próxima página, cómo la imagen transformada tiene la
apariencia de estar realmente dentro de un espacio de tres dimensiones. También
notemos que esta transformación genera un mejor aspecto que la que intentamos,
en el capítulo 4, al modificar un control DataGrid para conseguir una apariencia
de tres dimensiones. En ese caso, simulábamos este aspecto, pero el plano de pro-
yección no era necesariamente correcto.
Silverlight 3
337
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 337
Figura 2. Una imagen de dos dimensiones proyectada en un plano de tres.
Este tipo de proyecciones no sólo se aplica a imágenes, sino que pueden ser usadas
en cualquier control provisto por Silverlight. Otros atributos presentados por el
modelo de proyección se refieren al punto de proyección. Así como teníamos un
punto que representaba el eje de rotación de un elemento, este punto de proyec-
ción sitúa ese eje de proyección también dentro del espacio de tres dimensiones,
pudiendo modificar por completo el comportamiento y la visualización de los objetos.
Uso de Pixel Shader
Pixel Shader es un componente incluido en las actuales tarjetas de video presentes en
los equipos hogareños. Este componente funcional permite manipular y tratar la sali-
da del video a la pantalla, haciendo uso del procesador de la tarjeta video. Esto agiliza
la puesta en escena de las imágenes, permitiendo aplicar ciertos tratamientos a éstas,
antes de que sean mostradas. Como esta funcionalidad está impresa en el hardware de
la tarjeta, los cálculos sobre las modificaciones resultan más rápidos que los realizados
por líneas de código. Silverlight 3 hace uso de estas funcionalidades adicionando efec-
tos de video que luego serán traducidos y ejecutados por el hardware del usuario.
Image Source=”bosque_pokemon.jpg” Width=”400” Height=”250”
Image.Projection
PlaneProjection RotationX=”50”
RotationY=”30”
RotationZ=”35”
/PlaneProjection
/Image.Projection
Image.Effect
DropShadowEffect BlurRadius=”15”
ShadowDepth=”10”
/DropShadowEffect
/Image.Effect
/Image
APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN
338
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 338
En el caso anterior, aplicamos un efecto de sombra de manera dinámica, calculada en
el momento mediante Pixel Shader. Otro efecto disponible desde Silverlight 3 es el de
Blur o difuminado. Si bien estos dos los encontraremos incluidos por defecto y listos
para usar, es posible, si tenemos el conocimiento, elaborar efectos propios con Pixel
Shader, creando código en HLSL (High Level Shader Language o lenguaje de alto ni-
vel para Shader), compilándolo e incluyéndolo en la aplicación Silverlight.
Figura 3. Esta imagen cuenta con un cálculo
de sombra dinámica mediante la aplicación de Pixel Shader
Fuera del navegador
Si bien todo el entorno de ejecución de Silverlight se encuentra dentro del navegador,
la nueva versión nos permite configurar la aplicación fuera de él. Para esto, se requiere
el consentimiento del usuario y algo de configuración de nuestra parte. Esta caracte-
rística puede asestar un gran golpe a las típicas aplicaciones de escritorio, ya que con
Silverlight obtenemos gran potencial de diseño, trabajando en la Web, y además aho-
ra puede quedarse en el escritorio y ejecutarse desde éste. Podremos configurar estas ca-
racterísticas desde las propiedades del proyecto, como vemos en la siguiente figura:
Figura 4. Configuraciones necesarias
para utilizar la aplicación desde el escritorio.
Silverlight 3
339
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 339
Al instalar y ejecutar la aplicación desde el escritorio, veremos el mismo comporta-
miento sumando las características configuradas desde las propiedades del proyecto,
como se muestra en la Figura 5 y en la Figura 6.
Figura 5. Instalación de la aplicación Silverlight en nuestro escritorio.
Figura 6. La aplicación instalada, ahora puede
ser ejecutada sin necesidad de contar con el navegador web.
Silverlight 3 tiene aún muchas más novedades y sólo hemos visto algo superficial de
todas las nuevas características que presenta. Si ya estamos desarrollando con Sil-
verlight 2 y queremos ampliar nuestros horizontes en esta tecnología, lo que hemos
visto nos puede servir como un buen punto de partida para investigar y ahondar
más en Silverlight 3 y su nueva propuesta.
APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN
340
10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 340
Servicios
al lector
índice temático 342
Sitios web recomendados 345
En este apartado encontraremos una lista
de sitios web de alta utilidad para
iniciarnos en el desarrollo de aplicaciones
Silverlight, así como para obtener
información de soporte para poder crear
nuevas aplicaciones y quitar cualquier
velo de duda sobre la implementación
de código y la aplicación de técnicas
novedosas relacionadas con esta
tecnología.
Silverlight
SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 341
SERVICIOS AL LECTOR
342
Cookies 314
CookieSilver 315
CSS 178, 317
Cursor 88
D
Data 57, 218
DataContext 278
DataGrid 60, 68, 75, 132, 168, 231
DatePicker 60, 137, 147
DateTime 135, 145
Deep Zoom 199, 331
Depuración 62
Dibujar 213
Dibujo 46
DispatcherTimer 257
DisplayDate 143
DisplayMode 250
Distorsión 167
DLR 21
DoubleAnimation 171
E
Escalar 165
Estilo 178
Etiquetas 22, 290
Evento 72, 83, 261
Expression Blend 26, 30
F
Flash 15
FontFamily 127
FontSize 127
FontWeight 127
G
GetAttribute 294
GetElementById 294
ÍNDICE TEMÁTICO
A
AJAX 15
Almacenamiento aislado 239
Animaciones 19, 45, 170, 175
App.Config 271
AS 250
ASP.net 64, 317
Autocompletar 336
AutoUpgrade 58
B
Background 48
Barras de desplazamiento 98
Binding 276
BlackoutDates 142
Bool 135
Border 48, 101, 168, 183
BorderThickness 102
Button 67, 103, 183
C
Caja de texto 128
Calendar 60, 139
Canvas 24, 92, 222, 229
CheckBox 106, 123
Clases 40
Class 318
Click 51, 71, 74, 103, 107, 198
ClientBin 203
Clip 217, 225
CLR 21
ColorAnimation 173
ComboBox 117
Componentes 46, 67
Context 236
Contraseña 130
Controles 24
Controles 46, 67
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 342
GotFocus 84
Grid 67, 84, 89, 279
GridSplitter 89
Grilla 47
GroupName 110
H
Height 39, 85, 125, 302
Hilos 255
HLSL 339
Hojas de estilo 290, 317
HTA 83
HTML dinámico 15
HTML 290
HtmlDocument 292
HtmlPage 300, 323
HtmlWindow 305, 310, 323
HttpHandler 234
HyperlinkButton 113
I
IHttpHandler 236
IIS 270
Image 105, 114, 123, 215, 222
InkPresenter 208, 225
InnerHTML 295
INPUT 297
IntelliSense 61, 70
Interactividad 31
IsEnabledChanged 84
IsolatedStorageFile 240
IsolatedStorageFileStream 240
IsolatedStorageSettings 240
J
JavaScript 290, 320
Juego 222
K
KeyDown 84
KeyUp 84
L
LayoutUpdated 84
LinQ 21, 63, 74, 283
ListBox 124, 252
LostFocus 84
M
Marcador 196
Margin 68
MarkerReached 197
MediaElement 48, 188, 216
MediaOpened 198
Moonlight 330
MouseMove 209
N
Name 57
NavigateUri 113
Nodo 83
NoWrap 128
O
OnClick 321, 325
Onerror 57
OneTime 280
OneWay 280
OnExit 43
OnStartup 43
OpenFileDialog 251, 254
P
Param 57
Password 131
PasswordBox 130
PasswordChar 131
Pincel 211
Pixel Shader 338
Plantillas 58, 64, 178, 182
Plugin 56
PointAnimation 171
PopupWindow 308
Índice temático
343
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 343
TextWrapping 128
Threads 255
TimelineMarker 198
Timer 149, 256
Transformaciones 45, 158, 175
TransformGroup 158
Traslación 159
Trazado 218
T-SQL 74
TwoWay 280
U
Uri 225, 231, 238
URL 230
Usabilidad 31
V
Validadores 281
Video 194
VideoBrush 195
Visual Studio 24
W
WCF 21, 239, 270
Web.Config 234, 271
WebClient 230
WebMethod 264
Width 39, 85, 138, 302
WMA 188
WMV 194
WPF 16, 37, 82
X
XAML 16, 18, 21, 82, 148
XamlReader 238
XAP 114
XLinQ 230
XML 15, 22, 82
Z
Zoom 207
Position 190
ProgressBar 148, 258
Punto de interrupción 62
R
RadioButton 110, 123
Rotación 161
RSS 230
S
ScaleTransform 165
ScriptObject 324
ScrollViewer 98
SDK 58
Seguridad 239, 263
SelectedItem 119
SelectionMode 140, 146
Servicios web 222
SetAttribute 295
SetProperty 317
SetStyleAttribute 320
ShowDialog 251
Slider 152, 191
SOA 19
SOAP 265
Sonido 188
Source 50
SourceName 196
StackPanel 95, 168, 181, 237
Storyboard 173, 256
Streaming 21, 188, 228
String 281
Stroke 213
Subnodo 83
T
Tag 23, 82
Text 126, 183
TextBlock 24, 61, 120, 126, 153, 183, 236
TextBox 41, 67, 127
TextBoxStyle 45
SERVICIOS AL LECTOR
344
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 344
Sitios web recomendados
345
SITIOS WEB RECOMENDADOS
Memorabilia
http://memorabilia.hardrock.com
Hard Rock Café fue uno de los primeros sitios web en implementar la tecnología
Silverlight de Microsoft. Este sitio en particular presenta una colección completa de
objetos regalados por artistas dentro de una presentación Deep Zoom. Es reco-
mendable ver las estampillas de cartas enviadas por Paul McCartney.
PhotoSynth
http://photosynth.net
Este sitio web muestra el uso de la tecnología PhotoSynth creada por Microsoft
Research. Esta tecnología tiene la función de generar espacios en tres dimensiones
basados en fotografías. El software calculará los distintos puntos que componen un
espacio sobre la base de todas las imágenes disponibles de ese espacio.
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 345
SERVICIOS AL LECTOR
346
Bing
www.bing.com
El nuevo buscador de Microsoft incorpora funcionalidad creada con Silverlight para
interactuar con distintos servicios propuestos por la compañía. Es posible guardar las
búsquedas en SkyDrive, así como comentar y categorizar cada una de ellas.
Sitio oficial de Silverlight
www.silverlight.net
Sitio oficial de Silverlight, donde podremos encontrar todo tipo de ejemplos sobre
este software, así como herramientas y código pregenerado para usar en nuestros de-
sarrollos. No debemos olvidarnos de visitar la sala de videos educativos del sitio.
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 346
Sitios web recomendados
347
ComponentArt
www.componentart.com
Compañía que provee controles y componentes de alta calidad para usar en el de-
sarrollo de nuestras aplicaciones. Los últimos componentes creados por esta empresa
incluyen varios destinados al uso dentro de aplicaciones Silverlight (son pagos).
Infragistics
www.infragistics.com
Infragistics es otra empresa que provee controles y componentes visuales para el desa-
rrollo de aplicaciones. Presenta un gran abanico de controles para Silverlight listos pa-
ra usar. De igual forma que el sitio anterior, estos componentes y controles son pagos.
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 347
SERVICIOS AL LECTOR
348
Quince
http://quince.infragistics.com
Sitio propuesto por la empresa Infragistics que nos otorga una serie de patrones de
diseño visual para aplicar en nuestros desarrollos. Con Quince, es posible entender
cómo podemos mejorar la usabilidad de las aplicaciones desarrolladas por nosotros.
Librería MSDN
http://msdn.microsoft.com/en-us/library/cc838158(VS.95).aspx
La librería MSDN para Silverlight propuesta por Microsoft es el manual de referen-
cia a todas las clases, métodos, funciones, controles y componentes de Silverlight. Si te-
nemos alguna duda sobre el desarrollo para Silverlight, es necesario acudir a este sitio.
11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 348
Utilice nuestro sitio usershop.redusers.com:
• Vea información más detallada sobre cada libro de este catálogo.
• Obtenga un capítulo gratuito para evaluar la posible compra
de un ejemplar.
• Conozca qué opinaron otros lectores.
• Compre los libros sin moverse de su casa y con importantes
descuentos.
• Publique su comentario sobre el libro que leyó.
• Manténgase informado acerca de las últimas novedades y los
próximos lanzamientos.
También puede conseguir nuestros libros en kioscos o
puestos de periódicos, librerías, cadenas comerciales,
supermercados y casas de computación.
Compra Directa! usershop.redusers.com
usershop@redusers.com I ¥ (011) 4110.8700
V i s i t e n u e s t r o s i t i o w e b
usershop.redusers.com
Revise que haya un cuadro sobre el
autor, en el que se informe sobre su
experiencia en el tema.
En cuanto a la editorial, es conveniente
que sea especializada en computación.
1 Sobre el autor y la editorial
Compruebe que el libro tenga guías visuales,
explicaciones paso a paso, recuadros con
información adicional y gran cantidad de
pantallas. Su lectura será más ágil y
atractiva que la de un libro de puro texto.
2 Preste atención al diseño
Suele haber grandes diferencias de precio
entre libros del mismo tema; si no tiene el
valor en la tapa, pregunte y compare.
3 Compare precios
No sólo el del texto; también revise que las
pantallas incluidas en el libro estén en el
mismo idioma del programa que usted utiliza.
5 Verifique el idioma
Está en letra pequeña en las primeras
páginas; si es un libro traducido, la que vale
es la fecha de la edición original.
6 Revise la fecha de publicación
Desde un sitio exclusivo en la Red hasta
un CD-ROM, desde un Servicio de Atención
al Lector hasta la posibilidad de leer el
sumario en la Web para evaluar con
tranquilidad la compra, o la presencia de
adecuados índices temáticos, todo suma al
valor de un buen libro.
4 Tiene valores agregados??
Claves para comprar un libro
de computación.
Adquiéralo con todos los medios de pago
• Capítulo Gratis • Avant Première • Promoción • Ofertas
*
(*) Sólo válido para la República Argentina
Catalogo_200RespRedes.qxd 11/21/08 2:21 PM Page 381
Untitled-1 1Untitled-1 1 10/08/2009 12:28:3010/08/2009 12:28:30
Untitled-1 1Untitled-1 1 10/08/2009 12:37:1910/08/2009 12:37:19
Untitled-1 1Untitled-1 1 10/08/2009 12:56:1310/08/2009 12:56:13
LA PREPARACIÓN IDEAL PARA
DESARROLLADOR CINCO
ESTRELLAS DE MICROSOFT
Ésta es una obra teórica y práctica
para aprender a programar. Basado en
el curso Desarrollador Cinco Estrellas
de Microsoft, este material brinda las
habilidades necesarias para iniciar el
camino que nos lleve a convertirnos en
desarrolladores de la plataforma .NET.
DESARROLLADORES I 400 páginas
ISBN 978-987-1347-74-2
Adquiéralo con todos los medios de pago
• Capítulo GRATIS • Promoción • Ofertas •
usershop.redusers.com
RCT_Bombo_LIBROSilverlight.qxp 21/09/2009 16:10 Página 3
por MATÍAS IACONO
En este sitio encontrará una gran variedad de recursos y software relacionado,
que le servirán como complemento al contenido del libro. Además, tendrá la po-
sibilidad de estar en contacto con los editores, y de participar del foro de lecto-
res, en donde podrá intercambiar opiniones y experiencias.
Silverlight is the cross-platform, cross-browser plug-in
for rich interactive applications and cutting-edge
media experiences. With advanced tips from our
expert, this book provides practical, grounded advice,
and rich examples, to be ready for today´s challenges.
SILVERLIGHT
DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO
DE APLICACIONES PARA INTERNET
Desde su lanzamiento, Silverlight se convirtió rápidamente en la
opción multiplataforma ideal, tanto para desarrollar aplicaciones
enriquecidas e interactivas, como para generar experiencias
multimedia de vanguardia. Quien consiga dominarlo podrá ofrecer a
sus clientes aplicaciones visualmente impresionantes, tiempos de
respuesta sin comparación y requerimientos mínimos de ancho de
banda, todas ventajas acordes a los tiempos de la incipiente Web 3.0.
Esta obra ofrece un acercamiento profundo y práctico a esta
herramienta, y está dirigida a desarrolladores con conocimiento
de Microsoft .NET Framework, que deseen profundizar en el desa-
rrollo Web. La enorme experiencia de Matías Iacono como desa-
rrollador en esta plataforma lo convierte en el guía ideal para
aportar consejos prácticos bien fundados, ejemplos enriquecedo-
res y código optimizado para aplicar en sus propios proyectos.
CONTENIDO
N I V E L D E U S U A R I O
PRINCIPIANTE INTERMEDIO AVANZADO EXPERTO
1 | INTRODUCCIÓN A SILVERLIGHT
Experiencia de usuario y portabilidad | Arquitectura de
Silverlight 2 | Microsoft .NET Framework | Interfaz de usuario
y presentación | El código XAML | Herramientas de desarrollo
2 | MICROSOFT EXPRESSION BLEND 2
Silverlight con Expression Blend | Explorador de soluciones |
Entorno | Barra de herramientas | Crear nuestra primera
aplicación
3 | SILVERLIGHT PARA DESARROLLADORES
Puesta a punto de Visual Studio 2008 | Crear la primera
aplicación | Interoperabilidad con Expression Blend 2
4 | XAML AL EXTREMO
El lenguaje XAML | Declaración de objetos | Controles y
componentes | Grid | GridSplitter | Canvas | StackPanel |
ScrollViewer | Border | Controles de iteración con el usuario |
Button | CheckBox | RadioButton | HyperlinkButton | Image |
ComboBox | ListBox | TextBlock | TextBox | PasswordBox |
DataGrid | Calendar | DatePicker | ProgressBar | Slider
5 | LUZ, CÁMARA, ACCIÓN
Mover objetos | Transformaciones de traslación, rotación,
escalar y distorsión | Animaciones | DoubleAnimation |
ColorAnimation | Estilos y plantillas
6 | CERRAR EL CÍRCULO
MediaElement | Ejecutar sonidos | Elementos con video
embebido | Deep Zoom | Dibujar con InkPresenter | Áreas
de dibujo
7 | INTERCONEXIÓN
Ampliar las funcionalidades | Silverlight desde C# |
WebClient | Enviar información | Capacidad de
almacenamiento | OpenFileDialog | Manejo de hilos |
Temporizador | Hilos y eventos | Consumir servicios desde
Silverlight | Manipular datos | LinQ
8 | EL NAVEGADOR Y SU DOMINIO
Conectar tecnologías | Silverlight 2 y HTML | HtmlDocument
y HtmlElement | HtmlPage | HtmlWindow | Cookies |
Modificar CSS | Silverlight 2 y JavaScript | Llamar funciones
| Objetos para JavaScript
APÉNDICE A | SILVERLIGHT FUERA DE WINDOWS
APÉNDICE B | SILVERLIGHT 3, LA NUEVA GENERACIÓN
redusers.com
SILVERLIGHT
tapa Silverlight.qxp 21/09/2009 11:07 a.m. PÆgina 1

Silverlight

  • 1.
    • 1 ,j, "¡' j I I ¡' ,1" r , ¡' I I I l ' •j " I I APROVECHE AL MÁXIMO SU POTENCIAL ILIMITADO SILVERUGHT PARA DISEÑADORES Y DESARROLLADORES MICROSOFT EXPRESSION BLEND 2 Y MICROSOFT VISUAL STUDIO 2008 UNQ, WCFy SERVICIOS WEB CON C# CREACiÓN DE ANIMACIONES Y TÉCNICAS DE ESCRITURA PARA DISPOSITIVOS TÁCTILES INTERACCiÓN CON JAVASCRIPT, HTML, XML y CSS DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO DE APLICACIONES PARA INTERNET INCLUYE NOVEDADES DE LA VERSiÓN 3.0 por MATÍAS IACONO En este sitio encontrará una gran variedad de recursos y software relacionado, que le servirán como complemento al contenido del libro. Además, tendrá la po- sibilidad de estar en contacto con los editores, y de participar del foro de lecto- res, en donde podrá intercambiar opiniones y experiencias. Silverlight is the cross-platform, cross-browser plug-in for rich interactive applications and cutting-edge media experiences. With advanced tips from our expert, this book provides practical, grounded advice, and rich examples, to be ready for today´s challenges. SILVERLIGHT DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO DE APLICACIONES PARA INTERNETCONTENIDO N I V E L D E U S U A R I O PRINCIPIANTE INTERMEDIO AVANZADO EXPERTO 1 | INTRODUCCIÓN A SILVERLIGHT Experiencia de usuario y portabilidad | Arquitectura de Silverlight 2 | Microsoft .NET Framework | Interfaz de usuario y presentación | El código XAML | Herramientas de desarrollo 2 | MICROSOFT EXPRESSION BLEND 2 Silverlight con Expression Blend | Explorador de soluciones | Entorno | Barra de herramientas | Crear nuestra primera aplicación 3 | SILVERLIGHT PARA DESARROLLADORES Puesta a punto de Visual Studio 2008 | Crear la primera aplicación | Interoperabilidad con Expression Blend 2 4 | XAML AL EXTREMO El lenguaje XAML | Declaración de objetos | Controles y componentes | Grid | GridSplitter | Canvas | StackPanel | ScrollViewer | Border | Controles de iteración con el usuario | Button | CheckBox | RadioButton | HyperlinkButton | Image | ComboBox | ListBox | TextBlock | TextBox | PasswordBox | DataGrid | Calendar | DatePicker | ProgressBar | Slider 5 | LUZ, CÁMARA, ACCIÓN Mover objetos | Transformaciones de traslación, rotación, escalar y distorsión | Animaciones | DoubleAnimation | ColorAnimation | Estilos y plantillas 6 | CERRAR EL CÍRCULO MediaElement | Ejecutar sonidos | Elementos con video embebido | Deep Zoom | Dibujar con InkPresenter | Áreas de dibujo 7 | INTERCONEXIÓN Ampliar las funcionalidades | Silverlight desde C# | WebClient | Enviar información | Capacidad de almacenamiento | OpenFileDialog | Manejo de hilos | Temporizador | Hilos y eventos | Consumir servicios desde Silverlight | Manipular datos | LinQ 8 | EL NAVEGADOR Y SU DOMINIO Conectar tecnologías | Silverlight 2 y HTML | HtmlDocument y HtmlElement | HtmlPage | HtmlWindow | Cookies | Modificar CSS | Silverlight 2 y JavaScript | Llamar funciones | Objetos para JavaScript APÉNDICE A | SILVERLIGHT FUERA DE WINDOWS APÉNDICE B | SILVERLIGHT 3, LA NUEVA GENERACIÓN redusers.com SILVERLIGHT tapa Silverlight.qxp 21/09/2009 11:07 a.m. PÆgina 1
  • 2.
    CONÉCTESE CON LOSMEJORES LIBROS DE COMPUTACIÓN DESCUBRA EL POTENCIAL DE WINDOWS VISTA MANUALES USERS I 384 páginas I ISBN 978-987-1347-40-7 MANEJE LAS HERRAMIENTAS DE VISTA COMO UN EXPERTO MANUALES USERS I 352 páginas I ISBN 978-987-663-007-8 DESARROLLE APLICACIONES PARA WINDOWS Y LA WEB MANUALES .CODE I 368 páginas I ISBN 978-987-1347-32-2 usershop.redusers.com APRENDA A PROGRAMAR CON EL LENGUAJE MÁS POTENTE DESARROLLADORES I 400 páginas I ISBN 978-987-1347-76-6 RT_Bombo_LIBROSilverlight.qxp 21/09/2009 17:07 Página RT2
  • 3.
    DESCUBRA UN NUEVONIVEL EN EL DESARROLLO DE APLICACIONES PARA INTERNET 00_Silverlight.qxp 9/30/09 1:16 PM Page 1
  • 4.
    TÍTULO: SILVERLIGHT AUTOR: MatíasIacono COLECCIÓN: Manuales USERS FORMATO: 17 x 24 cm PÁGINAS: 352 Copyright © MMIX. Es una publicación de Gradi S.A. Hecho el depósito que marca la ley 11723. Todos los derechos reservados. No se permite la reproducción parcial o to- tal, el almacenamiento, el alquiler, la transmisión o la transformación de este libro, en cualquier forma o por cualquier medio, sea electrónico o mecánico, mediante foto- copias, digitalización u otros métodos, sin el permiso previo y escrito del editor. Su infracción está penada por las leyes 11723 y 25446. La editorial no asume responsa- bilidad alguna por cualquier consecuencia derivada de la fabricación, funcionamien- to y/o utilización de los servicios y productos que se describen y/o analizan. Todas las marcas mencionadas en este libro son propiedad exclusiva de sus respectivos due- ños. Impreso en Argentina. Libro de edición argentina. Primera impresión realizada en Sevagraf, Costa Rica 5226, Grand Bourg, Malvinas Argentinas, Pcia. de Buenos Aires en octubre de MMIX. ISBN 978-987-663-010-8 Iacono, Matías Silverlight. - 1a ed. - Banfield - Lomas de Zamora : Gradi, 2009. 352 p. ; 24x17 cm. - (Manual users; 175) ISBN 978-987-663-010-8 1. Informática. I. Título CDD 005.3 00_Silverlight.qxp 9/30/09 1:16 PM Page 2
  • 5.
  • 6.
    4 PRELIMINARES Matías Iacono Ingeniero desistemas, Microsoft Most Valuable Professional en ASP.net, Orador Regional para INETA Latam, Scrum Master cer- tificado y Microsoft Certified Technology Specialist. Cuenta con más de quince años de experiencia en el desarrollo de software con distintas tecnologías y metodologías. Ha dictado cerca de cincuenta conferencias técnicas en distintos países latinoamericanos, así como escrito y publicado artículos en numerosas publicaciones internacionales. Ha trabajado para empresas extranjeras de gran envergadura. En la actualidad, se desempeña como ingeniero de software para Mo- torola Argentina y es profesor en la Universidad Tecnológica Na- cional de Córdoba. Agradecimientos Agradezco a todos los amigos que me brindaron su apoyo y sus opiniones sobre lo escrito. A Miguel Saez, de Microsoft, por ha- berme facilitado material y a Lucas Ontivero, de Motorola Ar- gentina, por su crítica aguda, que me ayudó con el contenido pro- puesto en el libro. Dedicatoria A mi familia, por quedarse a mi lado largos fines de semana mien- tras concluía este libro. 00_Silverlight.qxp 9/30/09 1:16 PM Page 4
  • 7.
    5 PRÓLOGO Si hay algoa lo que le debemos la actual difusión de la tecnología informática, tan- to dentro del hogar como de las oficinas, es a la continua evolución de las interfa- ces gráficas de usuarios (GUI). Gracias a ellas, personas de todas las edades y pro- fesiones, en todo el mundo, pueden interactuar con equipos de computación para fines tan diversos como entretenerse, obtener información, realizar cálculos y co- municarse, entre un sinnúmero de otras posibilidades. Es seguro que tanto la constante innovación en el desarrollo de las interfaces grá- ficas como la aparición de Internet han sido los catalizadores para uno de los más fabulosos cambios en la manera en que las personas, alrededor del globo, se rela- cionan mediante el uso de la tecnología. Mientras que la Web seguirá siendo el ámbito de comunicación del futuro, es de es- perar que los requerimientos de interactividad entre máquinas y humanos se vuel- van aún más sofisticados y exigentes. Ante esto, Microsoft desarrolló Silverlight, una nueva apuesta para el desarrollo de elementos de gráficos de interacción con los usua- rios orientados a la Web. En este aspecto es, justamente, en el que esta obra hace un gran aporte, al presentar Silverlight 2.0 de una manera amena, clara y completa. En ella, se abarcan no sólo los pormenores técnicos de la tecnología, sino que, además, el autor se ha esmerado en brindar al lector un cúmulo de conocimientos que sólo podría obtenerse mediante la experiencia, todo esto reflejado en tips, datos útiles, recomendaciones, curiosida- des, advertencias y todos los consejos que el lector reconocerá como invaluables a la hora de adentrarse en esta apasionante tecnología. Por último, quisiera agradecer a Matías Iacono por este maravilloso trabajo que ha sido una guía segura en el aprendizaje de Silverlight y, con cuya lectura y estudio, me he sentido guiado y acompañado siempre. Lucas Ontivero Ingeniero de software, Motorola Argentina Prólogo 00_Silverlight.qxp 9/30/09 1:16 PM Page 5
  • 8.
    PRELIMINARES 66 EL LIBRO DEUN VISTAZO En esta obra se verán los conceptos principales para dominar Silverlight, la tecnología de Microsoft orientada al desarrollo de contenido dinámico y animaciones para la Web. El contenido está dirigido a desarrolladores con conocimiento de Microsoft .Net Framework, C# como lenguaje principal, y que dominen algunos conceptos de JavaScript y HTML. Capítulo 1 INTRODUCCIÓN A SILVERLIGHT 2 Para conocer Silverlight desde sus comienzos, en este capítulo describiremos su arquitectura. Hablaremos de las diferencias entre aplicaciones tradicionales y las nuevas aplicaciones visuales, y conoceremos la lista de herramientas necesarias para poder desarrollar aplicaciones Silverlight. Capítulo 2 MICROSOFT EXPRESSION BLEND 2 En este capítulo nos enfocaremos en Microsoft Expression Blend 2 como herramienta de desarrollo para Silverlight, orientada a diseñadores visuales y a diagramadores de aplicaciones. Daremos un paseo por la interfaz de Microsoft Expression Blend 2 y crearemos nuestra primera aplicación Silverlight. Este capítulo ayudará a los diseñadores y desarrolladores a entender cada uno de estos mundos. Capítulo 3 EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA Luego de enfocarnos en el diseñador visual, centraremos la atención de este capítulo en el desarrollador. Para esto, veremos qué posibilidades nos ofrece Microsoft Visual Studio 2008 para desarrollar aplicaciones Silverlight, los controles y componentes propuestos, su interfaz visual y los diferentes tipos de proyectos disponibles desde este entorno de desarrollo. Capítulo 4 XAML AL EXTREMO Cada uno de los controles y componentes proporcionados por Silverlight, su funcionalidad, eventos, métodos y funciones, serán vistos en este capítulo. Cada uno de estos elementos será descripto con profundidad, generando código de ejemplo por cada uno de ellos. Este capítulo representa una excelente guía de referencia sobre todos los componentes disponibles en Silverlight. Capítulo 5 LUZ, CÁMARA, ACCIÓN Gran parte de las prestaciones otorgadas por Silverlight incluyen la posibilidad de mover objetos dentro de nuestra aplicación. En este capítulo veremos cómo manipular esta característica, ya que se explicarán los distintos modelos disponibles para animaciones y transformaciones dentro de las aplicaciones Silverlight. Capítulo 6 CERRAR EL CÍRCULO Silverlight también otorga mucho potencial con el manejo de imágenes, video y sonido. En este capítulo hablaremos de ciertas características relacionadas con actividades 00_Silverlight.qxp 9/30/09 1:16 PM Page 6
  • 9.
    El libro deun vistazo 7 ! A lo largo de este manual encontrará una serie de recuadros que le brindarán información complementaria: curiosidades, trucos, ideas y consejos sobre los temas tratados. Cada recuadro está identificado con uno de los siguientes iconos: INFORMACIÓN COMPLEMENTARIA CURIOSIDADES E IDEAS DATOS ÚTILES Y NOVEDADES ATENCIÓN SITIOS WEB RRR,_` como consumir videos, mostrar imágenes o tocar sonidos dentro de las aplicaciones. También hablaremos de Deep Zoom y sus características, así como del dibujo a mano alzada con InkPresenter. Capítulo 7 INTERCONEXIÓN Este capítulo ofrece funcionalidades altamente valiosas. Crearemos un juego desde código C# y un lector de RSS, usaremos almacenamiento aislado para guardar información en el cliente, crearemos aplicaciones para subir archivos al servidor y culminaremos con la implementación de la última tecnología de interoperabilidad propuesta por Microsoft al conectar Silverlight con Windows Communication Foundation. Capítulo 8 EL NAVEGADOR Y SU DOMINIO Silverlight se ejecuta dentro de una página HTML manejada por el navegador web. Por tal motivo, posee gran potencial de interacción con el cliente. En este capítulo veremos cómo Silverlight puede manipular HTML así como intercambiar información con JavaScript. Además, conoceremos cómo JavaScript es capaz de consumir servicios generados desde Silverlight. Apéndice A SILVERLIGHT FUERA DE WINDOWS Gracias a MoonLight, Silverlight puede salir de Windows y trabajar en sistemas operativos basados en Linux y Unix. Hablaremos del proyecto MoonLight, sus características, limitaciones y el futuro de Silverlight como tecnología fuera de su ambiente nativo. Además, se presentan algunas herramientas gratuitas y de código libre que nos ayudarán en el desarrollo, tanto para Windows como para Linux. Apéndice B SILVERLIGHT 3, LA NUEVA GENERACIÓN Daremos un vistazo al producto recientemente lanzado por Microsoft. Silverlight 3 trae consigo valiosas mejoras al modelo ya planteado, las que enumeraremos para ganar conocimiento adicional por sobre lo ya aprendido durante todo el libro. Servicios al lector En esta última sección, encontraremos un índice que nos ayudará a buscar de forma rápida los términos más importantes de esta obra. Además, veremos un listado de sitios de interés para ampliar nuestros conocimientos y mantenernos al tanto de las últimas novedades en la materia. 00_Silverlight.qxp 9/30/09 1:16 PM Page 7
  • 10.
  • 11.
    Contenido 9 Sobre el autor4 Prólogo 5 El libro de un vistazo 6 Información complementaria 7 Introducción 12 Capítulo 1 INTRODUCCIÓN A SILVERLIGHT 2 Iniciarse en el mundo de Silverlight 2 14 Navegar hacia el mundo de Silverlight 2 14 La experiencia de usuario y la portabilidad 16 Arquitectura de Silverlight 2 19 Microsoft .Net Framework 20 Interfaz de usuario y presentación 21 El código XAML 22 Herramientas de desarrollo para Silverlight 2 24 Resumen 27 Actividades 28 Capítulo 2 MICROSOFT EXPRESSION BLEND 2 Un paseo por Expression Blend 2 30 Silverlight 2 con Expression Blend 2 30 Unir los extremos 32 Un recorrido por Expression Blend 2 37 Explorador de soluciones 38 Página inicial de Silverlight 2 39 La página App.xaml 40 El entorno de Expression Blend 2 43 La barra de herramientas 46 Crear nuestra primera aplicación con Expression Blend 2 48 Resumen 53 Actividades 54 Capítulo 3 EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA Silverlight para desarrolladores 56 Puesta a punto de Visual Studio 2008 56 Silverlight 2 con Visual Studio 59 Crear la primera aplicación con Visual Studio 2008 63 Interoperabilidad con Expression Blend 2 76 Resumen 79 Actividades 80 Capítulo 4 XAML AL EXTREMO El lenguaje XAML 82 ¿Qué es XAML? 82 Declaración de objetos 82 Controles y componentes 83 Controles contenedores y agrupadores 84 Control Grid 84 Control GridSplitter 89 Control Canvas 92 Control StackPanel 95 Control ScrollViewer 98 Control Border 101 Controles de interacción con el usuario 103 CONTENIDO 00_Silverlight.qxp 9/30/09 1:16 PM Page 9
  • 12.
    PRELIMINARES 10 Control Button 103 ControlCheckBox 106 Control RadioButton 110 Control HyperlinkButton 113 Control Image 114 Control ComboBox 117 Control ListBox 124 Control TextBlock 126 Control TextBox 127 Control PasswordBox 130 Control DataGrid 132 Control Calendar 139 Control DatePicker 147 Control ProgressBar 148 Control Slider 152 Resumen 153 Actividades 154 Capítulo 5 LUZ, CÁMARA, ACCIÓN Mover objetos 156 Transformaciones 158 Transformación de traslación 159 Transformación de rotación 161 Transformación escalar 165 Transformación de distorsión 167 Aplicar todas las transformaciones 168 Animaciones 170 DoubleAnimation 171 ColorAnimation 173 Animaciones y transformaciones 175 Estilos y plantillas 178 Estilos 178 Plantillas 182 Resumen 185 Actividades 186 Capítulo 6 CERRAR EL CÍRCULO MediaElement 188 Ejecutar sonidos 188 Video 194 Elementos con video embebido 195 Marcadores de video 196 Deep Zoom 199 Crear el primer Deep Zoom 200 Incluir Deep Zoom en Silverlight 203 Dibujar con InkPresenter 208 Dibujar en forma manual 212 Dibujar sobre otros elementos 215 InkPresenter y áreas de dibujo 217 Resumen 219 Actividades 220 Capítulo 7 INTERCONEXIÓN Ampliar las funcionalidades 222 Silverlight desde C# 222 00_Silverlight.qxp 9/30/09 1:16 PM Page 10
  • 13.
    Contenido 11 WebClient 230 Enviar información233 Almacenamiento aislado 239 Implementar el almacenamiento aislado 240 Capacidad de almacenamiento 245 Almacenar configuraciones 247 OpenFileDialog 251 Manejo de hilos 255 El concepto de hilos 256 Temporizador 257 Personalizar los hilos 259 Hilos y eventos 261 Consumir servicios desde Silverlight 263 Crear un servicio WCF 270 Manipular datos 275 Enlazado de datos 276 LinQ 283 Resumen 287 Actividades 288 Capítulo 8 EL NAVEGADOR Y SU DOMINIO Conectar tecnologías 290 Silverlight 2 y el HTML 290 HtmlDocument y HtmlElement 292 HtmlPage 301 HtmlWindow 307 Cookies 316 Modificar CSS 320 Silverlight 2 y JavaScript 323 Llamar funciones 325 Objetos Silverlight para JavaScript 327 Resumen 347 Actividades 348 Apéndice A SILVERLIGHT FUERA DE WINDOWS Proyecto Moonlight 330 Sistemas operativos 330 Versiones de Moonlight 331 Herramientas de desarrollo 331 Problemas conocidos 333 Apéndice B SILVERLIGHT 3, LA NUEVA GENERACIÓN Silverlight 3 336 Nuevos controles 336 Efectos en tres dimensiones 337 Uso de Pixel Shader 338 Fuera del navegador 339 Servicios al lector Índice temático 342 Sitios web recomendados 345 00_Silverlight.qxp 9/30/09 1:16 PM Page 11
  • 14.
    INTRODUCCIÓN Este libro estáorientado a desarrolladores de software, y diseñadores visuales y grá- ficos que deseen expandir su área de conocimiento de desarrollo hacia el ambiente web. Un lector con nociones iniciales podrá ver, durante los capítulos, una evolu- ción que le dará la oportunidad de aprender sin necesidad de saberes previos sobre la tecnología propuesta, Silverlight, mientras que aquel lector con experiencia po- drá encontrar en estas páginas una guía fundamental para aprender, con agilidad, conceptos sobre esta tecnología de Microsoft. Sin embargo, es necesario, para am- bos lectores, contar con conocimientos medios de desarrollo utilizando Microsoft C#, así como las técnica primordiales del funcionamiento y ejecución de la Web. Los temas propuestos en el libro fueron seleccionados para cubrir la mayor superfi- cie de conceptos sobre Silverlight 2, presentados de una manera progresiva de tal forma que el lector se sienta cómodo con su evolución y que aprenda a cada paso que da. Desde la recomendación y el uso de las herramientas ideales para el desa- rrollo bajo esta tecnología, tanto para diseñadores como para desarrolladores, gene- ramos ejemplos prácticos en cada capítulo, que abarcan desde HTML hasta C#, así como la aplicación de ASP.net y el uso de JavaScript. Silverlight es un modelo en ebullición. En el momento de lanzarse la versión 1, sus características eran limitadas; pero, al poco tiempo, Microsoft mejoró la tec- nología y sacó a relucir la segunda versión de Silverlight, versión de la que se ocupa este libro. Pero esta efervescencia, este cambio constante junto a la búsqueda de un mejor producto y de una tecnología superior, hicieron que, durante el tiem- po de escritura de este libro, Microsoft sacara la siguiente versión de Silverlight. En este momento, ya contamos con la versión 3 de Silverlight como una versión funcional y finalizada, por lo que incluimos un apartado, al final del libro, para in- troducir al lector en algunas de las nuevas funcionalidades provistas por Silverlight 3. De esta forma, con este texto, el lector no sólo aprenderá sobre Silverlight, sino que tendrá un bono extra al final, que le servirá de rampa de lanzamiento para abordar de lleno la nueva versión y permanecer siempre actualizado. PRELIMINARES 12 00_Silverlight.qxp 9/30/09 1:16 PM Page 12
  • 15.
    Introducción a Silverlight 2 Iniciarseen el mundo de Silverlight 2 14 Navegar hacia el mundo de Silverlight 2 14 La experiencia de usuario y la portabilidad 16 Arquitectura de Silverlight 2 19 Microsoft .Net Framework 20 Interfaz de usuario y presentación 21 El código XAML 22 Herramientas de desarrollo para Silverlight 2 24 Resumen 27 Actividades 28 Capítulo 1 En este primer capítulo veremos el porqué de Silverlight 2, al mismo tiempo que hablaremos de problemas comunes en el desarrollo de software desde la óptica de las interfaces gráficas, los diseñadores y programadores, así como las limitaciones de las herramientas usadas por cada uno. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 01_Silverlight.qxp 9/30/09 1:20 PM Page 13
  • 16.
    INICIARSE EN ELMUNDO DE SILVERLIGHT 2 Muchos cambios se han producido en el desarrollo web desde sus inicios. Se han sucedido mejoras sustanciales hasta la llegada de la Web 2.0 y, sin embargo, se si- guen buscando mejores formas y herramientas para trabajar en este fascinante mun- do. Recorramos esos años de evolución hasta la actualidad, cuando una de estas herramientas ve la luz para traer una solución a nuevas necesidades. Veamos, en este capítulo, los componentes clave de Silverlight 2: las herramientas de desarro- llo y diseño, su arquitectura y los elementos principales que le dan vida. Navegar hacia el mundo de Silverlight 2 Desde los inicios de la Web, ésta ha ido evolucionando, mutando y creciendo. Esta evolución se inició con la simple transferencia de texto, pasó por las imáge- nes y la captura de datos del usuario por parte del sistema, hasta llegar al manejo de contenido personalizado. Éste se genera para el usuario y por él, simulando casi el mismo comportamiento de aplicaciones desarrolladas para sistemas de es- critorio. Los cambios radicales en las tasas de transferencias de datos, así como en las capacidades de los equipos que servían esta información, también acom- pañaron dichos acontecimientos. Por supuesto, esta evolución no sólo fue de capa- cidades de hardware y prestaciones hacia el usuario. Al mismo tiempo, estuvo acom- pañada por software, lenguajes de programación y herramientas de desarrollo que, en conjunto, ayudaran a amortiguar la curva de complejidad sobre las necesida- des crecientes que tenían los sistemas. En definitiva, existían mayores requeri- mientos por parte de los usuarios y de los sistemas, por lo que la implementación en líneas de código y la puesta en marcha de los servicios necesitaron de herra- mientas que hicieran más simple este trabajo. En la actualidad, el desarrollo web está más pujante que nunca. Además, con el advenimiento de teorías (y prácticas) como el Cloud Computing o servicios de Internet totalmente dinámicos para correos electrónicos, confección de docu- mentos, redes sociales e interconexión de servicios, entre otros, debemos enten- der que la Web seguirá creciendo y mejorando durante mucho más tiempo. Esto nos llevará de vuelta a la idea antes tratada: mayor complejidad, mejoramiento en las herramientas y el soporte. Esta mejora en las herramientas que brindan soporte tanto al desarrollador como al diseñador se hace cada vez más necesaria y es mu- cho más requeridas por aquellos que se ven involucrados en el desarrollo web. De- bido a que desarrollar para la Web no se restringe al uso de una tecnología única y definitiva, el desarrollador web se ve en la necesidad imperativa de adquirir do- minio y conocimientos sobre decenas de tecnologías y lenguajes de programación, como XML, HTML, CSS, JavaScript, ActionScript, Lingo, PHP, C# y Java, entre muchas otras que forman el conjunto de la Web. Y es aquí donde se hace 1. INTRODUCCIÓN A SILVERLIGHT 2 14 01_Silverlight.qxp 9/30/09 1:20 PM Page 14
  • 17.
    visible Silverlight. Estesoftware forma parte de dicho crecimiento y sirve como solución, ya que plantea una mejor forma de desarrollar contenido dinámico pa- ra la Web. Esto sucede no sólo en lo visual, sino también como herramienta de desarrollo basado en tecnologías comunes ya conocidas. No debemos equivocarnos al pensar que Silverlight constituye la estrategia de Microsoft para competir con el ya popular Flash, ex de Macromedia, y ahora de Adobe. Por el contrario, Silverlight representa una oportunidad de reutilizar el co- nocimiento ya adquirido sobre código basado en Microsoft.Net Framework, un modelo que soporta no sólo lenguajes desarrollados y mantenidos por esta empresa, sino que cuenta, por el contrario, con el soporte de compañías creadoras de lengua- jes tan populares como Borland C# Builder y Delphi, también de Borland. De es- ta forma, Silverlight trae consigo la posibilidad de enriquecer la experiencia visual en el cliente web, trabajando en cualquiera de los navegadores de Internet más conocidos. Puede interactuar y ser modificado por lenguajes como JavaScript, ex- tendiendo el concepto de HTML dinámico y A.J.A.X. (Asynchronous JavaScript and XML o, en castellano, JavaScript asíncrono y XML). También puede consumir ser- vicios web o cualquier elemento con la capacidad de retornar XML, al mismo tiempo que puede ser programado o desarrollado mediante aquel lenguaje que usamos to- dos los días para nuestros desarrollos, o con el que nos sintamos más cómodos para generar las líneas de código que darán vida a nuestra aplicación. Figura 1. Microsoft .Net Framework es el nexo entre el sistema operativo y nuestro código. Nos ofrece una plataforma de ejecución, librerías de código, acceso a datos y soporte para diferentes lenguajes. VB C++ C# J# ... Common Language Specification VisualStudio.NET ADO .NET y XML Librería de clases base Common Language Runtime Sistema Operativo ASP .NET Web Forms • Web Services Mobile Internet Toolkit Windows Forms Iniciarse en el mundo de Silverlight 2 15 01_Silverlight.qxp 9/30/09 1:20 PM Page 15
  • 18.
    La experiencia deusuario y la portabilidad Antes de la aparición de Microsoft .Net Framework, construir una aplicación de soft- ware requería diferentes habilidades y dependía del ambiente en el cual se desarrollara esta aplicación. Así, si las aplicaciones necesitaban desarrollarse para ser usadas bajo Windows, éstas requerían que su diseño visual se creara de manera especial para este modelo. Al mismo tiempo, debería contemplar las limitaciones que el lenguaje de pro- gramación trajera consigo. El diseño, entonces, quedaba encapsulado dentro del códi- go del lenguaje seleccionado, siendo casi imposible su implementación en otro lenguaje o en una nueva versión del mismo. Pensemos que, si una aplicación debía ser migrada a una nueva versión del lenguaje o, por necesidades de negocio, debía ser implemen- tada en otro lenguaje, toda la interfaz visual debía ser reescrita e implementada. A lo anterior debíamos sumar que, si existía un cambio de ambiente, es decir, si movíamos el desarrollo a un dispositivo móvil o a la Web, no sólo la interfaz debía ser reescrita, sino que también debía cambiar la lógica radicada en el código. Esto no sólo acarrea reinversión de tiempo y dinero, sino que, además, la interfaz (y tal vez la lógica de ne- gocio) nunca quedaría del todo igual, castigando la experiencia del usuario que se ha- bía acostumbrado a una herramienta ya construida e implementada. Con la primera versión del .Net Framework, Microsoft hace el intento inicial de generar portabilidad entre ambientes y lenguajes, separando la interfaz gráfica del lenguaje de programación y proveyendo componentes comunes para que los am- bientes similares puedan reutilizar las interfaces ya creadas. Gracias a esto, teníamos aplicaciones creadas para Windows, que también funcionaban en dispositivos móviles, aunque aún quedaba trabajo por hacer en cuanto a desarrollo web y Windows, ya que estos dos ambientes seguían siendo incompatibles. Con la versión 3.0 de Microsoft .Net Framework, se introdujo un nuevo enfoque por medio de un es- quema XML para la confección y manipulación de interfaces de usuarios: ya no aparecían los típicos botones y cajas de texto rígidas comunes en cualquier aplica- ción de escritorio. Este esquema, llamado XAML (eXtensive Application Markup Language, o en castellano, Lenguaje Extensible de Formato para Aplicaciones) por sus siglas en inglés, le permitió al desarrollador crear otro tipo de aplicaciones a nivel visual. XAML fue explotado por WPF (Windows Presentation Foundation), pero muy rápido se entendió que XAML tenía mucho futuro por delante. 1. INTRODUCCIÓN A SILVERLIGHT 2 16 , La experiencia demuestra que la primera reacción por parte de los desarrolladores al ver Silverlight es asociarlo en forma directa con la competencia de Adobe Flash. Silverlight persigue objetivos similares, pero se separa de Adobe Flash en ciertos aspectos técnicos, como lengua- jes de programación y arquitectura. ¿QUÉ ES SILVERLIGHT? 01_Silverlight.qxp 9/30/09 1:20 PM Page 16
  • 19.
    Figura 2. CardSpace,WCF, WPF y WF (Workflow Foundation) se agregan como parte de Framework 3 sobre la versión 2 de Framework. Silverlight 2 usa, para la representación visual de sus elementos, XAML. Las mis- mas etiquetas que, como decíamos antes, también son soportadas por aplicaciones de escritorio construidas con WPF. Esto genera una ventaja significativa sobre la creación de aplicaciones y la adaptación del usuario a nuevas tecnologías. Pen- semos que, al tener un componente común como XAML para la representación visual de elementos de la interfaz gráfica, el esfuerzo aplicado para la creación de uno de estos componentes puede ser reutilizado y explotado en otros ambientes, no sólo en aquel para el cual Silverlight fue ideado. Pensemos entonces en una aplicación de escritorio, con cientos de usuarios que la usan durante meses o años y, de un momento a otro, se encuentran usando la misma aplicación, pero den- tro de un navegador web, con los mismos botones, el mismo contenido visual e igual comportamiento. Uno de los lados más rugosos en la implementación de un sistema está atado a la adopción de éste por parte del usuario, y es en los cambios de plataformas y ambientes donde se producen las discordias. Aquí es necesario Microsoft .NET Framework Versión 2.0 CardSpace WPF WCFWF Iniciarse en el mundo de Silverlight 2 17 _` Microsoft .Net Framework no sólo soporta los lenguajes de programación propuestos por Mi- crosoft. También podemos encontrar otros como Boo, Icc, Clarion#, Cobol, Corba, Eiffel, Fortran, Lisp, PHP, Perl y más. Esto puede resultar en especial interesante, ya que no necesitamos apren- der un nuevo lenguaje para desarrollar en Microsoft .Net Framework. MICROSOFT .NET Y LENGUAJES 01_Silverlight.qxp 9/30/09 1:20 PM Page 17
  • 20.
    invertir mayor esfuerzopara que esta nueva idea sea aceptada. Por tal motivo, nos hará falta toda la ayuda posible al momento de hacer este cambio. En la Web, las aplicaciones tienen más representatividad y, por ende, su atractivo y su facilidad de uso necesitan potenciarse. Esta mejora es llevada a cabo por la implementación de soluciones que conjugan JavaScript y XML, dando como pro- ducto la pieza conocida como A.J.A.X., donde bien podemos encontrar cientos de modelos listos para ser implementados. Pero el desarrollo sigue enfocándose en la manipulación del HTML que, sin desmerecer sus posibilidades, siempre llegará a un techo máximo, relacionado con las capacidades del mismo modelo HTML. En comparación con el modelo de aplicaciones de escritorio, la interactividad ofrecida por este último es muy superior a la que presenta HTML, y es aquí donde Silverlight, una vez más, explota lo mejor de estos dos mundos y lo lleva en forma directa al ámbito de aquel que pierde en comparación: el del HTML. Figura 3. Silverlight se nutre de cada una de las principales características de los dos mundos, generando una mejor experiencia de usuario e independencia en plataformas. Navegadores web CSS/HTML JavaScript/AJAX ASP.net Aplicaciones de escritorio XAML Framework .Net 1. INTRODUCCIÓN A SILVERLIGHT 2 18 RRR Es importante entender las diferencias entre las versiones de Microsoft .Net Framework. Sólo a partir de la versión 3, se incorpora el uso de XAML, así como WPF, pero el núcleo de este Fra- mework se mantiene idéntico al de la versión 2. Al desarrollar para cualquiera de estas nuevas plataformas, deberemos elegir una versión de Framework 3 o superior. VERSIONES DE MICROSOFT .NET FRAMEWORK 01_Silverlight.qxp 9/30/09 1:20 PM Page 18
  • 21.
    Como observamos enla Figura 3, Silverlight toma lo mejor de los dos mundos. Por un lado, los controles y componentes versátiles propuestos por el desarrollo de es- critorio y, por el otro, la portabilidad entre plataformas y la rapidez de la actuali- zación de aplicaciones a miles de usuarios al mismo tiempo que otorga Internet. Esta versatilidad y portabilidad entre plataformas, tanto de escritorio como web, no sería posible sin un lenguaje común de representación de controles. XAML es el lenguaje que nos dará esta posibilidad no sólo para el desarrollo, sino que también brinda la oportunidad de aumentar la versatilidad de las interfaces, poder llevar el comportamiento de las aplicaciones de escritorio a la Web, posibi- litar la adopción por parte del usuario final de manera independiente del sistema, mediante el aumento de la calidad y de la velocidad en el desarrollo, y otros pun- tos ganados con la utilización de XAML y Silverlight. Arquitectura de Silverlight 2 Al comienzo de nuestro recorrido, nombramos algunas de las características de Sil- verlight que, al mismo tiempo, definen su planteo arquitectónico. Dijimos que Silverlight está enfocado a la Web y que es ejecutado por el navegador web. Es- to se consigue gracias a un plugin o aditivo que hará las veces de gestor o in- térprete. Este componente ronda los 5 megabytes, lo que constituye una suma muy pequeña en relación con su potencia. En la actualidad, es soportado por los principales navegadores de Internet como Internet Explorer, FireFox y Safari, así como los sistemas operativos Windows (con base en Windows XP con Service Pack 2 y hasta Windows 7), Mac OS X 10+ y Linux. Pero Silverlight, aunque hemos hecho hincapié en la gestión de interfaces de usuario, no sólo es un lienzo donde podemos crear animaciones vectoriales, sino, muy por el contrario, consiste en una plataforma liviana de desarrollo con soporte para SOA (Service Oriented Architecture o, en castellano, Arquitectura Orientada a Servicios), re- des, manejo de datos, y más. Como observamos en la Figura 4, Silverlight va mucho más allá y nos entrega, por sobre todas las cosas, acceso a las últimas tecnologías y patrones de desarrollo de software. Podemos separar y enumerar las diferentes carac- terísticas sobre la base de su área de trabajo, como veremos a continuación. Iniciarse en el mundo de Silverlight 2 19 _` Por lo general, es difícil lograr que un usuario adopte una nueva aplicación cuando está acos- tumbrado a la que usa desde hace años. Este problema de adopción se ve potenciado en quienes nunca usaron una computadora. Pero, si podemos reproducir en el ordenador lo que el usuario está acostumbrado a utilizar en la vida real, la adopción será casi transparente. LA DIFÍCIL ADOPCIÓN POR PARTE DE LOS USUARIOS 01_Silverlight.qxp 9/30/09 1:20 PM Page 19
  • 22.
    Figura 4. Eneste diagrama podemos observar la arquitectura soporte completa de Silverlight 2. Microsoft .Net Framework Con respecto a las líneas de código y de clases ya implementadas para ser usadas por el desarrollador de código, el Framework disponible cubre todas las áreas necesarias para interactuar con datos y hasta con lenguajes propios de la Web. .NET para Silverlight Centro de presentación Manejo de navegador WCF REST RSS/ATOM SOAP Librería para Microsoft AJAX Motor JavaScript POX JSON WPF Controls Data Binding Layout Editing Data Motor de ejecución CLR XAML LINQ XLINQ XML Centro de interfaz gráfica Vector Animation Text Images Integrado con la red Integrado con DOM Servicio de aplicaciones Instalador Periféricos Keyboard Mouse Ink Multimedia VC1 WMA MP3 DRM Media BCC Generics Collections Cryptography Threading DLR Iron Python Iron Ruby Jscript 1. INTRODUCCIÓN A SILVERLIGHT 2 20 01_Silverlight.qxp 9/30/09 1:20 PM Page 20
  • 23.
    • LinQ yXLinQ: soporte especializado para llevar a cabo el manejo de colec- ciones de objetos, acceso a datos y XML. Con LinQ podremos crear consultas integradas con el lenguaje de programación. • WCF (Windows Communication Foundation): plataforma de comunicación para acceso a servicios web, servicios remotos y peticiones HTTP, entre otros. • Librería de clases base: acceso a las librerías de clases de Microsoft .Net Frame- work, que nos ofrece soporte para el manejo de cadenas de texto, expresiones regu- lares, serialización de datos, manejo de internacionalización de aplicaciones y más. • CLR (Common Language Runtime): motor de Microsoft .Net que se encarga del manejo de la memoria y demás puntos de contacto con el sistema operativo. • DLR (Dynamic Language Runtime, en castellano Lenguajes Dinámicos): soporte pa- ra lenguajes de programación como JavaScript, Iron Phyton e Iron Ruby. • Almacenamiento aislado: permite generar sectores de almacenamiento de archi- vos e información de manera aislada y para usuarios específicos. Interfaz de usuario y presentación Silverlight también presenta una gran cantidad de funcionalidad en cuanto a su pre- sentación visual y puede manejar sonidos, imágenes y videos, así como una serie de controles y componentes listos para usar. • Video y sonido: inclusión de soporte de formatos de video y sonido comunes co- mo MP3 y WMA. Incluye capacidades de streaming. • Imágenes: capacidad de despliegue de imágenes tanto vectoriales como mapas de bits en sus formatos más comunes, texto y animaciones. • Enlazado de datos: capacidad de enlazado de fuentes de datos automática que fa- cilita el despliegue de la información desde diferentes fuentes de datos. • Controles: set de controles listos para usar que brindan la posibilidad de crear nuestro propio set de controles y de reusarlos en diferentes aplicaciones. • XAML: implementación de eXtensible Application Markup Language para la con- fección de las interfaces. Éstas son creadas sobre la base de XML. Como pudimos ver hasta aquí, Silverlight no es un simple visualizador de ani- maciones, sino un avanzado complemento de desarrollo que hace uso de las principales tecnologías Microsoft y que permite desenvolvernos con soltura al momento de desarrollar aplicaciones sobre éste. Silverlight, entonces, nos ofrece la potencia de los lenguajes de programación uti- lizados, por lo general, en el desarrollo de aplicaciones de escritorio y web, ade- más, de su posibilidad de interacción con bases de datos y servicios remotos. También, nos brinda la elegancia de sus vistosas interfaces visuales, que pueden interactuar con lenguajes cliente, tales como JavaScript, enmarcado en un nave- gador web, sin estar atado a un sistema operativo ni a un navegador específico. Iniciarse en el mundo de Silverlight 2 21 01_Silverlight.qxp 9/30/09 1:20 PM Page 21
  • 24.
    Figura 5. Enla imagen, observamos los controles visuales listos para usar y su apariencia por defecto. El código XAML Ya hemos nombrado a XAML como uno de los componentes fundamentales de Silverlight, pero veamos un poco más en profundidad de qué se trata exactamen- te. XAML es un lenguaje declarativo, formado por etiquetas descriptivas para cada uno de los componentes que Silverlight pueda representar. XAML basa el concepto descriptivo en el conocido modelo de XML. Gracias a esta cualidad (ba- se de XML), entender la estructura de XAML resulta simple e intuitivo. Veamos a continuación un ejemplo de elementos XML simples: 1. INTRODUCCIÓN A SILVERLIGHT 2 22 RRR Debido a que Silverlight puede ser desarrollado con los principales lenguajes de programación soportados por Microsoft .Net Framework, éste brinda pleno soporte para la programación orien- tada a objetos y puede absorber todos los beneficios inherentes a este modelo de programación. PROGRAMACIÓN PROFESIONAL 01_Silverlight.qxp 9/30/09 1:20 PM Page 22
  • 25.
    <Contenedor> <Elemento Atributo=”Valor”> Contenido delElemento </Elemento> </Contenedor> Etiquetas o tags descriptivas dentro de caracteres < y >. Cada elemento es iniciado con un nombre específico y siempre deberemos señalar su cierre utilizando el mismo nom- bre más los caracteres </, lo que especificará la finalización del tag. En el ejemplo, tam- bién podemos notar cómo un elemento puede contener otros elementos, así como atri- butos descriptivos y valores dentro del mismo nodo. XAML sigue este mismo patrón: <Canvas Width=”300” Height=”300” Background=”Brown”> <TextBlock x:Name=”Texto” Text=”Hola Mundo!”></TextBlock> </Canvas> El ejemplo en XAML nos demuestra que la estructura es similar al del que hemos usado para XML, con la salvedad de que las etiquetas o tags ya se encuentran defi- nidas y asociadas a los elementos visuales que representan. En el ejemplo, colocamos un contenedor que tendrá un tamaño en ancho y en alto de 300 pixeles, y color de fondo azul. Dentro de este contenedor, encontramos otro control utilizado para la visualización de textos, que mostrará la frase Hola Mundo! en pantalla. Figura 6. Resultado de nuestra primera prueba con XAML y Silverlight. Iniciarse en el mundo de Silverlight 2 23 01_Silverlight.qxp 9/30/09 1:20 PM Page 23
  • 26.
    El ejemplo nossirve, al mismo tiempo, para mostrar otros atributos importantes den- tro del mundo de XAML y de Silverlight. Tanto el elemento Canvas como TextBlock son controles preestablecidos por el entorno de Silverlight. Canvas es utilizado para definir un elemento contenedor de otros componentes, y TextBlock nos da la posibilidad de mostrar texto en pantalla en forma de bloques. La combinación de estos elementos produce lo que aparece en la Figura 6, pero el concepto va más allá porque muestra cómo, anidando elementos, podemos conseguir diferentes efectos visuales. Así, es posible mezclar un control del tipo botón con un control utilizado para mostrar imágenes o videos y obtener como resultado un botón en cuyo fondo se reproduce un video. Por último, el atributo x:Name es el que le otorga, al con- trol, la capacidad de tener un nombre único, descriptivo, que podrá ser usado por el lenguaje de programación que elijamos para darle funcionalidad a la interfaz vi- sual. Con este atributo, podremos cambiar el texto representado al principio en tiem- po de ejecución, sobre la base de la reacción de un evento por parte del usuario o por parte del flujo de nuestra aplicación. A medida que avancemos en el libro, nos introduciremos dentro de XAML; también en los diferentes componentes y con- troles disponibles por parte del entorno de desarrollo y librerías de objetos. Herramientas de desarrollo para Silverlight 2 Si tenemos en cuenta que una de las principales cualidades de Silverlight es el poten- ciamiento visual en interfaces de usuario, sería muy interesante contar con herramien- tas para su correcto diseño y diagramación. Así, de manera sencilla, nos guiarían en la confección de los elementos XAML, su estructura, controles anidados, enlazado a fuen- tes de datos, entre otros. Microsoft nos provee de dos herramientas principales, cada una de ellas enfocada a cubrir una de las ramas involucradas en la generación de ele- mentos Silverlight. Por un lado, para desarrolladores de software, la herramienta por excelencia es Microsoft Visual Studio en su versión 2008. Aunque la nueva versión de esta herramienta puede obtenerse con facilidad (Visual Studio 10), la que hemos nombrado es suficiente para emprender nuestra labor. Microsoft Visual Studio 2008 resultará ideal debido a su soporte de Microsoft .Net Framework 3.5, herramienta que trae consigo una serie de plantillas para Silverlight 2. 1. INTRODUCCIÓN A SILVERLIGHT 2 24 RRR Gracias a la extensibilidad de XML como lenguaje de etiquetas es que XAML genera un nuevo sub- conjunto de estas etiquetas para la representación de controles en el entorno de Silverlight. Así lo hace flexible en la creación de los elementos, fácil de entender y portable entre ambientes. XAML Y XML 01_Silverlight.qxp 9/30/09 1:20 PM Page 24
  • 27.
    Figura 7. VisualStudio 2008 otorga pleno soporte para Silverlight 2 mediante plantillas como las que observamos en la imagen. De cualquier manera, tendremos que instalar, además de la herramienta mencio- nada, el Service Pack 1 para ésta. La instalación del Service Pack 1, junto con la de las herramientas de desarrollo de Silverlight 2, incluirán en Visual Studio 2008 las plantillas de la Figura 7. Debido a que la versión 2 de Silverlight vio la luz después que la herramienta de desarrollo, este procedimiento resulta la única forma de po- der ver los asistentes y demás componentes dentro de la mencionada herramienta. Además de las plantillas que acelerarán el desarrollo, podremos encontrar una serie de controles y componentes para su uso inmediato que, si bien, como veremos más ade- lante, es posible construirlos por nuestra cuenta desde cero, toda la lógica de funcio- nalidad ya se encuentra contenida y probada en ellos. Esto nos ahorra tiempo de tra- bajo al no tener que desarrollar algo ya existente. Componentes como botones, calendarios y cajas de texto son sólo algunos de los que encontraremos dentro del aba- nico de posibilidades. Como vemos en la Figura 8, Visual Studio 2008 nos presenta una lista completa de controles listos para usar que, como ya dijimos, tienen toda la lógica que necesitarán impresa en el mismo componente, y, además, está pronta para usar. Iniciarse en el mundo de Silverlight 2 25 Además del Service Pack 1 para Visual Studio 2008, también deberíamos contar con el con- junto de herramientas de Silverlight. Éstas pueden ser descargadas desde la dirección www.microsoft.com/downloads, ingresando Silverlight 2 tools for Visual Studio 2008 como criterio de búsqueda. DESCARGA DE SILVERLIGHT 2 TOOLS PARA VISUAL STUDIO 2008 01_Silverlight.qxp 9/30/09 1:20 PM Page 25
  • 28.
    Figura 8. Grillas,cajas de texto y listas desplegables son sólo algunos de los controles listos para usar incluidos en Visual Studio 2008. Por otro lado, también existe una herramienta para diseñadores gráficos que no cuenten con experiencia en el desarrollo de software. Con una interfaz similar a la de herramientas para manejo fotográfico, Microsoft Expression Blend 2 le permite al diseñador gráfico, y por qué no al desarrollador, construir XAML de manera rápida y amigable, como toda herramienta WYSIWYG (What you see is what you get o en castellano Lo que ves es lo que obtienes) por sus siglas en in- glés. Esto quiere decir que, al trabajar con Microsoft Expression Blend 2, el diseño que planteemos será igual al resultado final en el momento de ejecución de la aplicación de Silverlight. Deberemos usar Microsoft Expression Blend 2 si estamos habituados a la creación de imágenes vectoriales o si sólo buscamos ace- lerar el desarrollo de componentes Silverlight. Veremos más a fondo las cualida- des de Microsoft Expression Blend 2 a lo largo de los capítulos, con suficiente detalle como para poder utilizarlo con cierta seguridad. Por último, cabe mencionar que Microsoft Visual Studio 2008 y Microsoft Ex- pression Blend 2 se compenetran de tal forma que, por lo común, nos veremos creando código en la primera herramienta, abriendo y editando el mismo pro- yecto en la segunda, para terminar con algunos retoques artísticos o acelerar el enlazado de datos en nuestro trabajo. En la Figura 9, podemos observar cómo un proyecto creado en Visual Studio 2008 puede ser abierto y manipulado en for- ma directa con Microsoft Expression Blend 2. Debido al mismo motivo citado en el caso de Visual Studio 2008, es necesario instalar un conjunto de herramientas en Microsoft Expression Blend 2 para con- tar con plantillas que den soporte a Silverlight 2. En este caso, el Service Pack 1 para Microsoft Expression Blend 2 nos otorgará la prestación. 1. INTRODUCCIÓN A SILVERLIGHT 2 26 01_Silverlight.qxp 9/30/09 1:20 PM Page 26
  • 29.
    Figura 9. MicrosoftExpression Blend 2 trabajando sobre una solución creada en Microsoft Visual Studio 2008. A lo largo del libro haremos referencia a estas dos herramientas, que serán usadas para los distintos ejemplos que plantearemos. Por tal motivo, es recomendable con- tar con las herramientas instaladas en nuestro equipo antes de continuar con los siguientes capítulos. Es posible también realizar los ejemplos con las versiones gra- tuitas de Visual Studio 2008 (Visual Studio 2008 Express), aunque no podemos garantizar que los ejemplos de interfaz y otros aspectos concuerden con lo que los usuarios de estas versiones verán en sus equipos. Iniciarse en el mundo de Silverlight 2 27 … RESUMEN Silverlight puede ser una herramienta extremadamente potente con soporte basado en Microsoft .Net Framework, que nos otorga la posibilidad de desarrollar en el lenguaje y la forma que mejor nos convenga. Desde la versión 1 de Silverlight hasta la actual, ha habido mejoras notables, con mayor funcionalidad y prestaciones tanto para el desarrollador como para el diseñador visual. El usuario final se ve beneficiado al tener que descargar un plugin de tamaño pequeño y que trabaja en casi todos los navegadores y sistemas operativos de la actualidad. 01_Silverlight.qxp 9/30/09 1:20 PM Page 27
  • 30.
    28 PREGUNTAS TEÓRICAS 1 ¿Enqué modelo se basa el código XAML pa- ra representar los elementos de la interfaz? 2 ¿Subconjunto de qué otro modelo de desa- rrollo visual para Windows podríamos con- siderar a Silverlight? 3 ¿Qué versión de Microsoft .Net Framework necesitamos, como mínimo, para trabajar con Silverlight 2.0? 4 ¿Qué sistemas operativos y navegadores web soportan la ejecución de Silverlight 2.0? 5 ¿Qué herramienta resulta ideal para desa- rrolladores, que les permita potenciar el desarrollo de aplicaciones Silverlight 2.0? 6 ¿Los diseñadores visuales cuentan con al- guna herramienta de software que los ayu- de a crear contenido para Silverlight 2.0? 7 ¿Es necesario instalar algún aditamento en la herramienta de desarrollo? 8 ¿Silverlight 2.0 provee algún conjunto de componentes listos para usar? 9 ¿Por qué es importante crear interfaces atractivas e intuitivas en las aplicaciones? 10¿Cómo se llama el modelo de desarrollo para la Web que conjuga el uso de XML y JavaScript? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Diríjase al sitio web de la W3C (www. w3.org/XML) para aprender más sobre XML. 2 Para introducirse mejor en el mundo de Silverlight, intente ampliar el ejemplo pro- puesto en este capítulo, modificando el tipo de fuente y el color de fondo de la apli- cación creada. 3 Para conocer más sobre desarrollo con Microsoft .Net, tome el curso gratuito del Desarrollador 5 Estrellas desde el sitio web de Microsoft. Este curso ayuda a en- tender términos utilizados en este libro. La URL es www.mslatam.com/latam/msdn/ comunidad/dce2005. 4 Instale Microsoft Expression Blend 2 y déjelo listo para trabajar en el siguiente capítulo. 5 Una vez instalados Visual Studio 2008 y Microsoft Expression Blend 2, ingrese en www.silverlight.net, el sitio oficial de Silverlight, descargue los ejemplos y analícelos. Esto ayuda a entender con mayor facilidad esta tecnología. 01_Silverlight.qxp 9/30/09 1:20 PM Page 28
  • 31.
    Microsoft Expression Blend 2 Un paseopor Expression Blend 2 30 Silverlight 2 con Expression Blend 2 30 Unir los extremos 32 Un recorrido por Expression Blend 2 37 Explorador de soluciones 38 Página inicial de Silverlight 2 39 La página App.xaml 40 El entorno de Expression Blend 2 43 La barra de herramientas 46 Crear nuestra primera aplicación con Expression Blend 2 48 Resumen 53 Actividades 54 Capítulo 2 ¿Cuáles son las herramientas disponibles para desarrollar aplicaciones Silverlight? ¿Cómo podemos aumentar nuestra productividad a la hora de escribir XAML? Éstas son algunas de las preguntas que abordaremos en este capítulo. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 02_Silverlight.qxp 9/30/09 1:23 PM Page 29
  • 32.
    UN PASEO POREXPRESSION BLEND 2 En el capítulo anterior, nos introdujimos en el mundo de Silverlight 2. Vimos algunas de sus características, los elementos que lo componen y las principales he- rramientas de desarrollo usadas para la creación de aplicaciones y componentes de Silverlight. Una de estas herramientas, Microsoft Expression Blend 2, es usada por los diseñadores visuales y por los desarrolladores como un suplemento para los detalles visuales avanzados. En este capítulo, ahondaremos en el uso de esta herramienta y su interacción con Silverlight 2, cómo crear animaciones así como también elementos compuestos, para finalizar con la creación de nuestra primera aplicación Silverlight 2. Este contenido está dirigido, en especial, a diseñadores visuales que quieran incursionar en el uso de Expression Blend 2 como herramienta de diseño para software y a desarrolladores de software que necesiten modificar, de manera rápida, interfaces visuales basadas en XAML. Silverlight 2 con Expression Blend 2 Desde los inicios de su desarrollo, este software siempre se enfocó, de manera prioritaria, en las líneas de código y en la solución del problema propuesto. Es- to sucede ya que, justamente, fueron el código y el problema por corregir los que motivaron la creación de soluciones de software, que provean una respuesta programática a la dificultad planteada. Este enfoque, el de la solución del problema, causó que en el desarrollo de software primara la capacidad y la calidad de reso- lución de un problema por encima del enfoque interactivo entre la aplicación y el ejecutor de ese programa. Así, dentro de la historia del software y las compu- tadoras, por carencias o por el enfoque antes citado, el trabajo se hacía mediante tarjetas perforadas, las cuales se apilaban en grandes cajas y que poseían, en sí mis- mas, la resolución de una de las partes que solucionaba el todo del problema. Sin ninguna duda, este sistema era manejado sólo por el desarrollador de este software primario y no por alguien ajeno a la informática de la época. Desde ese momen- to de la historia y hasta la actualidad, se produjeron cambios en la manera en que el usuario interactuaba entonces e interactúa ahora con esta pieza de software. Sin 2. MICROSOFT EXPRESSION BLEND 2 30 _` A pesar de más de 40 años de evolución en la ingeniería de software, sólo en la actualidad se po- ne especial énfasis en las interfaces visuales y en cómo éstas pueden ser parte de la solución del problema al que el usuario se debe enfrentar a diario. Así, vemos aparecer nuevas tecnolo- gías multitáctiles en sistemas operativos, o de captura de movimientos en consolas de juegos. LA EVOLUCIÓN DE LAS INTERFACES 02_Silverlight.qxp 9/30/09 1:23 PM Page 30
  • 33.
    embargo, éste seguiríaencontrándose una y otra vez ante una herramienta que, aunque en esencia cubriera sus necesidades funcionales y resolviera el dominio del problema planteado, no abarcaría los conceptos de usabilidad, ergonomía visual o interactividad entre el hombre y la máquina. Figura 1. En el Mix 2009 realizado por Microsoft, uno de los temas por tratar fue la creación de interfaces gráficas. Después de algunas décadas marcadas por este comportamiento de parte de la ingeniería de software y de aquellos que la han practicado, de alguna forma, el usuario terminó acostumbrándose a la idea de obtener aplicaciones o piezas de software que aparecen, como grandes hitos visuales y pantallas monocromáticas. Esto sucede, incluso, en pleno auge de las tarjetas aceleradoras de video con capacidades vi- suales que diez años atrás se reservaban sólo a inmensos ordenadores destinados a la producción de efectos cinematográficos. Muy pocos desarrolladores de software contemporáneos, incluidas las empresas, contemplan como parte de sus desarro- llos la inclusión de esta temática. Sólo con la llegada de la Web, algunos de ellos adicionaron esto como una necesidad comercial, pero, en muy pocos casos, co- mo una realidad para brindar un mejor producto que, además de solucionar un Un paseo por Expression Blend 2 31 , Es importante incluir en los proyectos de desarrollo de software a un diseñador gráfico que cuente con experiencia en interfaces de usuario. No debemos desestimar este punto en nues- tros desarrollos. El éxito de nuestro producto no está marcado sólo por las líneas de código, la usabilidad es un aspecto muy importante. CONSULTEMOS A UN DISEÑADOR 02_Silverlight.qxp 9/30/09 1:23 PM Page 31
  • 34.
    problema, resulte optimizadoen lo que a interactividad con el usuario se refiere. Por supuesto, la implantación de este concepto dentro del desarrollo de software acarreó ciertos problemas que han tenido que ser resueltos por fuerza bruta más que por inteligencia, debido a que la solución planteada, la de incorporar mejoras vi- suales e interactivas, requiere de la presencia de otras ciencias. Esas ciencias están alejadas del desarrollo de software, por lo que el problema resulta bastante claro al tener que unir, de alguna forma, extremos que hablan idiomas diferentes. Unir los extremos En la actualidad, el mayor impedimento en la creación de aplicaciones visuales y el trabajo realizado por los expertos en esta materia es causado por las herramien- tas que éstos utilizan. Cuando en un proyecto de software es necesaria la interven- ción de diseñadores gráficos especializados en experiencia de usuario, éstos plasman su trabajo en herramientas más ligadas a las doctrinas del diseño gráfico y las artes visuales que a las del desarrollo de software. Entonces, el problema recae en que tanto el diseñador como el desarrollador hablan idiomas diferentes: los primeros se refieren a colores, movimiento, disposición de elementos y formas, entre otros aspectos, mientras que los segundos necesitan saber qué mostrar y cómo se reali- zará el código que contenga la lógica. Al mismo tiempo, los diseñadores suelen desconocer las limitaciones de las plataformas donde serán creados los productos de software y tienden a generar elementos visuales extremadamente atractivos, pe- ro con costos elevados en su implementación por parte del desarrollador. Al final y sin ser lo último, el producto resultante del diseñador será un conjunto de imá- genes o un esquema que mostrará lo pretendido de manera visual para la aplica- ción de software, y le deja al desarrollador la tarea de volver a armar esto dentro de las líneas de código, quien no lo conseguirá con exactitud al compararlo con lo propuesto en un principio por el diseñador. Y es aquí donde han surgido herramientas que traducen, de alguna forma, esto que el diseñador piensa y plasma en algo que el desarrollador pueda usar. Así, es posible encontrar herramientas muy potentes como Adobe Fireworks donde, por medio del modelo visual creado por el diseñador, el desarrollador obtiene un conjunto de imágenes y código HTML. A pesar de eso, este tipo de herramientas acarrea un problema, ya que se enfocan en el diseñador y no en el desarrollador, creando código HTML que, basado en el dibujo propuesto, generan HTML poco útil para su implementación, como podemos ver a continuación. El siguiente es el resultado HTML generado para la Figura 2. tr tdimg src=”images/spacer.gif” width=”103” height=”1” border=”0”alt=”” //td 2. MICROSOFT EXPRESSION BLEND 2 32 02_Silverlight.qxp 9/30/09 1:23 PM Page 32
  • 35.
    td [...41 líneas eliminadas...] td colspan=”2”img name=”Untitled1_r4_c1” src=”images/Untitled- 1_r4_c1.gif” width=”112” height=”60” border=”0” id=”Untitled1_r4_c1” alt=”” //td tdimg src=”images/spacer.gif” width=”1” height=”60” border=”0” alt=”” //td /tr Y, si bien este código puede ayudar, resulta imposible de usar para el desarrollador, por lo que éste se verá forzado a reescribir partes o su totalidad para poder obtener código que le sea útil. Para esto utilizará sólo código HTML, debido a que a éste se le pueden agregar cuestiones programáticas a diferencia del anterior. spanFiltro de búsqueda/span br select option/option option/option option/option /select Figura 2. A la derecha podemos ver lo que consiguió el desarrollador como resultado del concepto ideado por el diseñador. Un paseo por Expression Blend 2 33 02_Silverlight.qxp 9/30/09 1:23 PM Page 33
  • 36.
    El problema esclaro: estas herramientas hacen las veces de traductores, pero no de ge- neradores. Traducen lo que el diseñador quiso decir a algo que el desarrollador pueda entender, pero, en este proceso de traducción, las herramientas no traducen funciona- lidad, por lo que el desarrollador no la obtendrá y deberá retraducirla por su cuenta. La diferencia sustancial sobre este concepto por parte de Expression Blend 2 reside en que no es un traductor, sino un generador de funcionalidad, con la característica de que para el diseñador la herramienta se comportará como cualquier otra herra- mienta de las que está acostumbrado a usar. Sin embargo, a medida que diagrama y diseña los contenidos visuales, ésta generará funcionalidad lista para ser implementa- da por el desarrollador de software, como podemos observar en el siguiente código: Grid x:Name=”LayoutRoot” Background=”White” TextBlock Height=”23” HorizontalAlignment=”Left” Margin=”96,32,0,0” VerticalAlignment=”Top” Width=”174” Text=”Filtro de búsqueda” TextWrapping=”Wrap” FontFamily=”Aharoni” FontSize=”18”/ ComboBox Height=”42” HorizontalAlignment=”Left” Margin=”96,59,0,0” Style=”{StaticResource ComboBoxStyle1}” VerticalAlignment=”Top” Width=”160” OpacityMask=”{x:Null}” ComboBox.Foreground LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FFF36767”/ GradientStop Color=”#FFFFFFFF” Offset=”1”/ /LinearGradientBrush /ComboBox.Foreground ComboBox.Background LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FFC07070”/ GradientStop Color=”#FF0F0000” Offset=”1”/ /LinearGradientBrush 2. MICROSOFT EXPRESSION BLEND 2 34 _` Existen especializaciones en el desarrollo de software que se enfocan en la optimización de las interfaces visuales, llegando al punto de calcular la cantidad de clics que deberá hacer un usuario para conseguir realizar una acción determinada. La implementación de estas técnicas produce mayor aceptación de los productos por parte de los usuarios. OPTIMIZACIÓN DE LA INTERFAZ 02_Silverlight.qxp 9/30/09 1:23 PM Page 34
  • 37.
    /ComboBox.Background /ComboBox /Grid El diseñador verá,en lugar del código anterior, un modelo como el que se mues- tra en la figura que aparece a continuación: Figura 3. Una lista desplegable creada con Expression Blend 2, que generará código XAML listo para ser usado por el desarrollador. Como el desarrollador obtiene código que se adapta a sus necesidades, puede en- focarse directamente en la solución del problema. A modo de ejemplo, en las si- guientes líneas de código vemos cómo el desarrollador agrega algunas líneas de código C# en la clase asociada al código XAML para generar funcionalidad so- bre el producto del diseñador: public partial class Page : UserControl { public Page() { // Required to initialize variables InitializeComponent(); this.ComboBox.Items.Add(“Item 1”); this.ComboBox.Items.Add(“Item 2”); Un paseo por Expression Blend 2 35 02_Silverlight.qxp 9/30/09 1:23 PM Page 35
  • 38.
    this.ComboBox.Items.Add(“Item 3”); } } El resultadode esta implementación de código podemos verlo a continuación: Figura 4. Como observamos en esta imagen, el resultado propuesto por el diseñador y la implementación del desarrollador son idénticas. Microsoft Expression Blend 2, entonces, sirve de nexo entre los dos elementos involucrados en el desarrollo, tanto para diseñadores como para desarrolladores. De esta manera se logra que los productos resultantes en ambos casos sean com- patibles entre sí, para que ninguno de los profesionales involucrados tenga la ne- cesidad de salir de su ámbito natural de trabajo. El resultado final será, entonces, que el diseñador obtendrá en la pieza de software el comportamiento y la apariencia visual, tal como los había ideado, mientras que el desarrollador no se verá forzado a intentar traducir estas ideas a elementos programáticos y se dedicará exclusiva- mente a la funcionalidad y a la resolución del problema. 2. MICROSOFT EXPRESSION BLEND 2 36 RRR Contar con un diseño visual de la aplicación de manera temprana no sólo sincronizará a los miembros del equipo de desarrollo, ya que todos tendrán una idea general del producto final, sino que puede servir de disparador de retroalimentación por parte del cliente al ver con antelación la idea del producto terminado. PROTOTIPO DEL PRODUCTO 02_Silverlight.qxp 9/30/09 1:23 PM Page 36
  • 39.
    Un recorrido porExpression Blend 2 Al iniciar Expression Blend 2 o al crear un nuevo proyecto con él, podemos elegir entre cuatro tipos diferentes. Tenemos dos proyectos específicos para Silverlight y sus diferentes versiones, pero también podemos diseñar y trabajar con proyectos Windows Presentation Foundation (WPF). • Aplicación WPF: este tipo de proyecto representa una aplicación de escritorio con soporte para WPF. Si tenemos en cuenta que WPF también se compone de código XAML, es posible crear un entorno visual directamente desde Expression Blend 2. • Librería de controles WPF: esta librería de controles está especializada en el en- capsulamiento de elementos XAML y código de programación para su posterior reutilización en aplicaciones WPF. Debemos optar por esta opción cuando quere- mos crear elementos reutilizables para ser incorporados en distintas aplicaciones. • Sitio de Silverlight 1: este tipo de proyectos está orientado a crear sitios web con soporte para la versión 1 de Silverlight. Debemos tener en cuenta que este modelo no es tratado en este libro y además representa una versión antigua del software. • Aplicación de Silverlight 2: una vez instalado el Service Pack 1 para Expression Blend 2, podremos ver esta clase de trabajos. Éste es el tipo de proyectos sobre los cuales nos moveremos, tanto de manera visual como programática. Figura 5. Lista de proyectos incluidos en Expression Blend 2. Un paseo por Expression Blend 2 37 , La mayoría de los controles preestablecidos en Silverlight presentarán un comportamiento si- milar al de sus homónimos presentes en el desarrollo web y de escritorio. Al interactuar con ellos se deberá, por consiguiente, imitar las mismas líneas de código usadas en los demás ambientes de desarrollo con Microsoft .Net. CONTROLES EN SILVERLIGHT 02_Silverlight.qxp 9/30/09 1:23 PM Page 37
  • 40.
    Además de poderindicar el nombre del proyecto que vamos a crear y la ubica- ción física que tendrá, es posible seleccionar el lenguaje de programación con el cual preferimos trabajar. Vale aclarar que, para poder conseguir esta lista, es ne- cesario haber instalado esos lenguajes en nuestra estación de trabajo. El hecho de poder seleccionar un lenguaje de programación se refiere a que cualquier código que se realice desde Expression Blend 2 se hará en ese lenguaje, por lo que es im- portante elegir aquel con el que estemos más familiarizados. Explorador de soluciones Una vez que hemos creado el proyecto Silverlight 2, podremos navegar entre sus archivos desde el explorador de la solución, que típicamente puede ser encontrado a la derecha de la aplicación, como podemos observar en la Figura 6. Este explorador nos mostrará, como elementos iniciales, una página del tipo XAML más una clase creada en el lenguaje seleccionado, en este caso C#. Esta clase de C# es la que será usada para generar el código que maneje los elementos creados en la página XAML. Figura 6. El explorador de soluciones (área superior derecha) de Expression Blend 2 con los elementos iniciales de una aplicación Silverlight 2. 2. MICROSOFT EXPRESSION BLEND 2 38 RRR Para mejorar nuestro desarrollo en Expression Blend 2, es recomendable tener instalado, ade- más, alguna de las herramientas de desarrollo de software de Microsoft, como por ejemplo Visual Studio 2008. Esto hará que, de tener que agregar código de programación a nuestro pro- yecto Silverlight, lo podamos hacer con mayor facilidad desde estas herramientas. INTEROPERABILIDAD 02_Silverlight.qxp 9/30/09 1:23 PM Page 38
  • 41.
    Página inicial deSilverlight 2 El archivo Page.xaml es considerado la página o componente de inicio para nuestra aplicación Silverlight 2, teniendo como contenido el siguiente código: UserControl xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” x:Class=”SilverlightApplication2.Page” Width=”640” Height=”480” Grid x:Name=”LayoutRoot” Background=”White”/ /UserControl En el caso de Silverlight 2, el elemento inicial es representado por un tag llamado UserControl. Lo que nos dice esto es que no será considerado como una apli- cación en sí misma, sino como un componente que puede ser incrustado o con- sumido por otras aplicaciones del tipo Silverlight, así como por aplicaciones web. En la misma declaración de atributos de este control Silverlight, se incluye el nombre de la clase de C# encargada de manejar los componentes del control, así como el ancho y el alto, en pixeles, del control. Si exploramos el contenido de esa clase, podremos ver lo siguiente: using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; Un paseo por Expression Blend 2 39 RRR Es posible hacer que nuestro control Silverlight se adapte a la superficie que lo contiene. Si co- locamos el elemento Silverlight dentro de una tabla HTML y configuramos las propiedades del elemento para que sus atributos Width y Height sean igual a Auto, éste se adaptará de manera automática a las dimensiones de su contenedor. DIMENSIONES DE SILVERLIGHT 02_Silverlight.qxp 9/30/09 1:23 PM Page 39
  • 42.
    using System.Windows.Shapes; namespace SilverlightApplication2 { publicpartial class Page : UserControl { public Page() { // Required to initialize variables InitializeComponent(); } } } Esta clase, como ya comentamos, es la que será usada como contenedor de la implementación del código que interactuará con los componentes colocados en la página XAML previamente vista. Esto quiere decir que, si queremos que nuestra aplicación Silverlight consuma datos de una base de datos o reaccione apoyada en estímulos por parte del usuario, deberíamos escribir esas líneas dentro de esta clase. Por supuesto, no estamos obligados a acumular todas las líneas de código en este único archivo ya que, como en todo lenguaje orientado a objetos, podremos crear tantas clases como necesitemos sin estar obligados a tener una página XAML por cada una. Así, podríamos encapsular la lógica de negocios o el acceso a datos en clases especializadas, y generar código mantenible y fácilmente modificable. La página App.xaml La página App.xaml, junto con la clase de código que la representa, es otro de los archivos creados inicialmente. Esta clase es usada en especial para almacenar có- digo XAML, que en el caso de App.xaml puede ser reusado dentro de todas las demás páginas de tipo XAML. Como podemos ver en el siguiente código: 2. MICROSOFT EXPRESSION BLEND 2 40 , Como una buena práctica en el desarrollo de software, encontramos los patrones de diseño de software. Éstos representan formas de crear código para solucionar problemas específicos. Es importante tener presente estos patrones para mejorar la calidad del código creado en Silverlight. Como resultado, obtendremos código más prolijo y más fácil de modificar. PATRONES DE DISEÑO DE SOFTWARE 02_Silverlight.qxp 9/30/09 1:23 PM Page 40
  • 43.
    Application.Resources !— Resources scopedat the Application level should be defined here. — Style x:Key=”TextBoxStyle1” TargetType=”TextBox” Setter Property=”BorderThickness” Value=”1”/ Setter Property=”Background” Setter.Value LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FFE8EFF1”/ GradientStop Color=”#FF87DFF4” Offset=”1”/ /LinearGradientBrush /Setter.Value /Setter Setter Property=”Foreground” Value=”#FFFF0000”/ Setter Property=”Padding” Value=”2”/ Setter Property=”BorderBrush” ... ... En el código anterior, el archivo App.xaml es usado para alojar la definición de un nuevo elemento TextBox, que presenta ciertas particularidades de sus atributos de color y comportamiento, como podemos ver en la Figura 7. Este nuevo elemento, ahora, puede ser accedido y consumido por cualquier otro TextBox que se en- cuentre dentro de nuestra aplicación. Por lo común, cuando desarrollemos con Silverlight, tendremos la necesidad de crear nuestros propios esquemas visuales para que sean aplicados sobre controles específicos. Una forma de compartir estos esquemas es mediante su colocación dentro de este archivo. De cualquier manera, hablaremos más de estos esquemas y propiedades en los capítulos 4 y 5. Un paseo por Expression Blend 2 41 RRR Debemos tener cuidado en la cantidad de información que agregamos a nuestros archivos XAML, ya que éstos deben ser descargados por el usuario. Un archivo de gran tamaño tomará más tiempo en ser descargado, en detrimento de la experiencia del usuario. Podemos usar carga por demanda para mejorar esta experiencia. TAMAÑO DE ARCHIVOS 02_Silverlight.qxp 9/30/09 1:23 PM Page 41
  • 44.
    Figura 7. Elesquema generado puede ser aplicado a otros controles del mismo tipo en cualquier otra página de Silverlight. Con respecto a la página de código (App.xaml.cs), podemos decir que presenta un conjunto de eventos que se dispararán en determinados momentos de la vi- da de nuestra aplicación. El código genérico se muestra a continuación, y luego lo analizaremos con más detalle: public App() { this.Startup += this.OnStartup; this.Exit += this.OnExit; this.UnhandledException += this.Application_UnhandledException; InitializeComponent(); } private void OnStartup(object sender, StartupEventArgs e) { // Load the main control here this.RootVisual = new Page(); } private void OnExit(object sender, EventArgs e) { } 2. MICROSOFT EXPRESSION BLEND 2 42 02_Silverlight.qxp 9/30/09 1:23 PM Page 42
  • 45.
    El primer método,constructor de esta clase, se encarga de enlazar eventos inhe- rentes al comportamiento de nuestra aplicación. El método OnStartup se ejecutará al inicio de la aplicación, en este caso, podríamos colocar código en él para con- seguir algún comportamiento necesario al momento de inicializarse nuestra apli- cación. Por ejemplo, podríamos necesitar inicializar objetos o conectarnos a un servicio web, entre otras posibilidades. En el mismo caso, el evento OnExit será dis- parado en el momento en el que la aplicación sea cerrada o terminada, y de igual forma que en el caso anterior, podríamos necesitar liberar ciertos recursos o realizar acciones específicas cuando la aplicación concluya. El entorno de Expression Blend 2 El entorno de Expression Blend 2 no se limita a los archivos previamente tratados. Si tenemos en cuenta que esta herramienta puede ser usada tanto por diseñadores como por desarrolladores, podremos encontrar elementos útiles para los dos casos. Una de las secciones destacadas involucra el lienzo de dibujo central. En este lien- zo, podremos arrojar y ordenar todos los controles incluidos en Silverlight, así co- mo crear nuestros propios modelos y controles. Figura 8. En este lienzo, podemos ver cómo son manipulados distintos controles de manera visual. Desde esta área central, también es posible interactuar en forma directa con el código XAML. En nuestra interfaz podemos ver, en la parte superior derecha, las opciones para intercambiar entre los diferentes modos de visualización: Diseño, XAML o Dividir (mixto), y tenemos la posibilidad de modificar los componentes desde cualquiera de estas vistas. Si contamos con cierta experiencia en edición de Un paseo por Expression Blend 2 43 02_Silverlight.qxp 9/30/09 1:23 PM Page 43
  • 46.
    XAML, es probableque trabajemos en el modo mixto o de pantalla dividida, ya que esto puede acelerar nuestro trabajo de manera significativa. El próximo grupo de paneles que vamos a inspeccionar es el de las propiedades. Éste se encuentra situado a la derecha de Expression Blend 2. Típicamente, estas propiedades son el acceso rápido a las configuraciones de aspecto y comportamiento de los controles adicionados al lienzo de edición. Para lograr la inspección de las propiedades de un control, primero será necesario seleccionarlo. Según el control seleccionado, las propiedades se verán afectadas en relación a éste por lo que no con- taremos con las mismas opciones en todos los casos. Figura 9. Existen otras propiedades relacionadas con diferentes controles, sólo debemos movernos usando la barra de desplazamiento ubicada a la derecha. En esta área también podemos encontrar, en la parte superior, opciones que tengan que ver con el proyecto. En especial, la pestaña relacionada con los recursos de la aplicación, donde se listarán todos los atributos previamente configurados, como los alojados en el archivo App.xaml, que ya hemos tratado. La gran venta- ja de esta lista de recursos radica en que podemos arrastrar cualquiera de estos 2. MICROSOFT EXPRESSION BLEND 2 44 RRR En Silverlight, no sólo es posible modificar la apariencia visual de los controles nativos mediante la generación de esquemas. También podremos crear nuestros propios componentes y controles heredándolos en nuestro propio código y creando nueva lógica funcional. IMPLEMENTACIÓN DE CONTROLES 02_Silverlight.qxp 9/30/09 1:23 PM Page 44
  • 47.
    elementos sobre algunode los controles existentes para aplicar las configuracio- nes a ese control. El resultado de arrastrar el estilo configurado al inicio permite obtener lo que podemos ver en la siguiente figura. Figura 10. El control de caja de texto posee, una vez aplicado, el estilo definido en el elemento TextBoxStyle1, que aparece debajo de la pestaña de recursos. El último panel que agrupa información sobre nuestra aplicación Silverlight se en- cuentra a la izquierda del lienzo de dibujo. Sobre estos grupos, en la parte superior, se ubican las transformaciones y animaciones de los componentes de nuestra aplica- ción. Aunque hablaremos de estas propiedades con mayor detalle en el capítulo 5, vale recalcar que se pueden generar diferentes efectos de movimiento y transformaciones desde esta sección. Debajo de este panel, se encuentra el árbol de controles de la pá- gina que estamos visualizando. Los controles se agruparán de manera jerárquica sobre la base del contenedor inmediato superior. Si tenemos en cuenta que los controles XAML pueden ser contenedores de otros controles XAML, esta estructura nos dará rápido acceso a cada uno de los elementos que componen un control de manera rápi- da. En la Figura 11, podemos ver un ejemplo de este árbol y del panel de animaciones. Un paseo por Expression Blend 2 45 _` Todas las imágenes, videos y sonidos que agreguemos a nuestro proyecto, así como cualquier archivo externo, serán comprimidos en un único archivo final con extensión XAP. Este archivo es, en realidad, un archivo zip que contiene todos los elementos creados por el proyecto Silverlight. COMPRESIÓN DE ARCHIVOS 02_Silverlight.qxp 9/30/09 1:23 PM Page 45
  • 48.
    Figura 11. Eneste árbol de controles se muestra la lista de elementos agregados antes a nuestro lienzo de dibujo, cómo éstos son contenidos por una grilla y ésta, a su vez, por el control Silverlight. La barra de herramientas Desde la barra de herramientas de Expression Blend 2, tendremos acceso a todos los controles y componentes preestablecidos de Silverlight y de Microsoft .Net Framework. Podemos separar la lista de controles en los siguientes grupos: • Elementos de dibujo: son aquellos que nos dan acceso a herramientas de dibujo vectoriales. Con éstos, podremos dibujar líneas, curvas, círculos y rectángulos. Figura 12. Listas de controles para dibujo vectorial. • Contenedores y agrupadores: la tarea de estos elementos consiste, principal- mente, en agrupar otros controles Silverlight, aunque también se encargan de ordenar, dentro de la superficie de dibujo, la disposición de esos elementos. Así, 2. MICROSOFT EXPRESSION BLEND 2 46 02_Silverlight.qxp 9/30/09 1:23 PM Page 46
  • 49.
    podemos encontrar grillas,donde se definirán filas y columnas (agregando den- tro de cada celda distintos controles y componentes) o elementos de barras de desplazamiento para colocar contenido que exceda los límites de ancho o alto de- finidos para una zona de nuestra aplicación. Figura 13. Controles para la agrupación y contención de otros elementos y controles. • Interacción con el usuario: este último grupo representa aquellos controles y componentes que sirven para capturar comportamiento por parte del usuario. Dentro de los más conocidos, podemos encontrar los botones, cajas de texto, lis- tas desplegables y botones de selección múltiple, entre otros. Figura 14. Controles más comunes para capturar información por parte del usuario. Los controles antes nombrados suelen ser los que se usan con mayor frecuencia para el desarrollo de aplicaciones con Silverlight, pero existen otros que no se ven de forma di- recta. Para poder acceder a ellos, es necesario seleccionar el último elemento de la lista en la barra de herramientas. Al hacerlo, podremos ver la lista completa de controles dis- ponibles y agregarlos a nuestra colección de controles, como se muestra a continuación. Un paseo por Expression Blend 2 47 02_Silverlight.qxp 9/30/09 1:23 PM Page 47
  • 50.
    Figura 15. Todoslos controles disponibles desde Expression Blend 2. Crear nuestra primera aplicación con Expression Blend 2 Ya estamos en condiciones de comenzar a trabajar con Expression Blend 2 para crear nuestra primera aplicación Silverlight. En este caso, crearemos un visor simple de videos. Este visor deberá contemplar las posibilidades de iniciar, pausar y detener, en forma completa, una película designada por nosotros. El primer paso es crear una nueva aplicación Silverlight 2. Una vez hecho esto, necesitaremos agregar a nuestro lienzo de dibujo un control del tipo MediaElement, que sirve para representar videos, imágenes y sonidos en Silverlight. Para poder agregar este control, es necesario que lo busquemos en la lista completa de controles Silverlight, como vimos en la Figura 15, ya que no se encuentra disponible en la barra de herramientas. Junto con este control, agregaremos alguno del tipo Border. Este control es necesario para darle una apa- riencia de caja a nuestra película, debido aque el control MediaElement no posee características. Podemos obtener un cambio en la configuración visual del control Border si modificamos sus características en la pestaña Propiedades. Para este caso, 2. MICROSOFT EXPRESSION BLEND 2 48 _` A medida que Silverlight va madurando, más empresas y portales en la Web se inclinan por la utilización de esta tecnología sobre otras. Uno de los últimos portales que optó por modi- ficar toda su implementación de servicios para los usuarios fue Terra, al cambiar su utilización de Adobe Flash por Silverlight. CADA VEZ MÁS SE INCLINAN POR SILVERLIGHT 02_Silverlight.qxp 9/30/09 1:23 PM Page 48
  • 51.
    debemos modificar laspropiedades del fondo (Background), para que se aplique el color degradado, y las de apariencia, colocando el grosor del borde del control (BorderThikness) en 1 y el radio de curvatura de las esquinas (CornerRadius) en 10. Figura 16. Propiedades aplicadas al control Border. Por último, el control MediaElement debe ser contenido por el control que representa el borde configurado previamente. Para esto, arrastramos el control MediaElement den- tro del control Border para lograr el efecto deseado. Como podemos editar directamente XAML, es posible lograr el mismo fin con las siguientes líneas de código: Border Margin=”95.5,57,91.5,217” BorderBrush=”#FF000000” BorderThickness=”1,1,1,1” CornerRadius=”10,10,10,10” Border.Background LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FF6985B5”/ GradientStop Color=”#FFFFFFFF” Offset=”1”/ /LinearGradientBrush /Border.Background MediaElement Height=”Auto” Width=”Auto” OpacityMask=”{x:Null}”/ /Border Por último, es necesario que agreguemos tres botones para las tres acciones antes definidas. Podremos cambiarle el texto que se va a mostrar en cada botón, presio- nando dos veces con el puntero del ratón sobre el control, o mediante sus propie- dades. El resultado debería ser similar al mostrado en la siguiente figura. Un paseo por Expression Blend 2 49 02_Silverlight.qxp 9/30/09 1:23 PM Page 49
  • 52.
    Figura 17. Nuestrovisor de videos con los botones que controlarán la reproducción. Una vez conseguido el visor de videos, es necesario configurar el control MediaElement para especificarle cuál será el video que se va a reproducir. Seleccionamos el con- trol MediaElement en la lista de propiedades y buscamos la fuente de contenido (Source). Por lo general, podremos seleccionar formatos soportados por Silverlight de los que hablaremos con más detalles en el capítulo 6 cuando veamos el compo- nente MediaElement de manera especial. Una vez que hemos seleccionado el video en cuestión, presionamos la tecla F5 para inicializar la aplicación. Esta acción de- berá iniciar un explorador de Internet y desplegar la aplicación creada. Podremos notar que el video se reproduce con normalidad, pero los botones creados para ca- da una de las acciones no funcionan como esperábamos, debido a que no hemos generado ningún código que las realice (Figura 18). Para conseguirlo, el primer paso es asignarle un nombre a nuestro MediaElement, ya que sin él no podremos acceder a las propiedades del control, por lo que no se- rá posible iniciarlo, pausarlo o detenerlo. Podemos asignarle el nombre al control seleccionándolo y agregándole el mismo que tiene en la lista de propiedades o me- diante XAML por medio del atributo x:Name=”Nombre del Control”. El elemento MediaElement quedará como se ve en el siguiente código: 2. MICROSOFT EXPRESSION BLEND 2 50 RRR Si necesitamos buscar material sobre desarrollo de interfaces visuales, es posible que también las encontremos mediante la sigla UX (User eXperience o experiencia de usuario, por su signifi- cado en inglés). Debido a que el término, con el tiempo, mutó, tendremos más chances de hallar información mediante este último nombre. INTERFACES DE USUARIO 02_Silverlight.qxp 9/30/09 1:23 PM Page 50
  • 53.
    MediaElement Height=”Auto” Width=”Auto”Source=”silverlight.wmv” AutoPlay=”False” x:Name=”visorVideo”/ Figura 18. El visor de videos trabajando de manera correcta en nuestro navegador. Si tenemos en cuenta que la lógica debe ser creada en la clase de código C#, necesita- remos escribir algunas líneas en ella para realizar las acciones propuestas por los tres botones. Tenemos varios caminos para lograrlo: podríamos usar Visual Studio 2008 para generar el código. Visual Studio 2008 es una herramienta de alto nivel para la creación de código para aplicaciones, así como para realizar pruebas sobre él. Por otro lado, sería posible modificar el archivo de clase y el código XAML por nuestra cuen- ta. Sin embargo, esto puede redundar en un aumento de trabajo y del tiempo de desarrollo y crear posibles problemas en la confección del código, si no somos expe- rimentados conocedores del lenguaje de programación utilizado. De cualquier ma- nera, para este ejemplo, si optamos por la segunda opción, sólo deberemos seguir unos cuantos pasos. Primero, en el código XAML, tendremos que agregar el atributo Click=”Nombre del Método” por cada botón creado. Click representa el evento por el Un paseo por Expression Blend 2 51 RRR Expression Blend 2 trae consigo un pequeño servidor de páginas web. Este servidor es activado en el momento en que queremos depurar nuestro trabajo y ver los resultados obtenidos. Gra- cias a este servidor, no dependeremos de grandes infraestructuras para desplegar y ejecutar nuestros proyectos cada vez que necesitemos validar lo que estemos desarrollando. SERVIDOR WEB 02_Silverlight.qxp 9/30/09 1:23 PM Page 51
  • 54.
    cual se dispararála acción o la lógica contenida en el método o función creada en el código C#. Así, cuando el usuario presione el botón en cuestión, el evento Click será disparado y se desencadenará toda la lógica que hayamos programado. Es necesario, entonces, que modifiquemos nuestro XAML para agregar los tres eventos: Button Height=”33” HorizontalAlignment=”Left” Margin=”95.5,0,0,162” VerticalAlignment=”Bottom” Width=”76.5” Content=”Iniciar” RenderTransformOrigin=”0.481,0.515” Click=”Iniciar”/ Button Height=”33” HorizontalAlignment=”Left” Margin=”193,0,0,162” VerticalAlignment=”Bottom” Width=”76.5” RenderTransformOrigin=”0.481,0.515” Content=”Pausar” Click=”Pausar”/ Button Height=”33” Margin=”287,0,276,162” VerticalAlignment=”Bottom” Width=”76.5” RenderTransformOrigin=”0.5,0.5” Content=”Detener” Click=”Detener”/ Estos tres eventos ahora hacen referencia a tres funciones: Iniciar, Pausar y Detener. Pa- ra agregar la lógica que maneje estas acciones, necesitamos modificar nuestra clase C#. Si no contamos con Visual Studio 2008, podremos abrirla con el bloc de notas o cual- quier editor de texto. El resultado final debería ser como el que sigue: using System; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace SilverlightApplication2 { public partial class Page : UserControl { public Page() { 2. MICROSOFT EXPRESSION BLEND 2 52 02_Silverlight.qxp 9/30/09 1:23 PM Page 52
  • 55.
    // Required toinitialize variables InitializeComponent(); } private void Iniciar(object sender, RoutedEventArgs e) { visorVideo.Play(); } private void Pausar(object sender, RoutedEventArgs e) { visorVideo.Pause(); } private void Detener(object sender, RoutedEventArgs e) { visorVideo.Stop(); } } } En el código anterior, vemos cómo una simple línea de código por acción pue- de ejecutar, pausar o detener el video. Si volvemos a ejecutar nuestra aplicación Silverlight, deberemos poder interactuar con el video seleccionado mediante los botones, iniciándolo, deteniéndolo y pausándolo. Un paseo por Expression Blend 2 53 … RESUMEN Expression Blend 2 es una herramienta altamente flexible que une dos áreas del desarrollo de software que habían estado separadas y con falta de comunicación. De esta forma les da tanto a los diseñadores como a los desarrolladores una forma de comunicarse para que los primeros puedan ver plasmadas sus ideas en las aplicaciones tal cual las han concebido, y los desarrolladores implementen estas ideas sin la necesidad de reescribir código, para no invertir tiempo y esfuerzo de manera innecesaria. 02_Silverlight.qxp 9/30/09 1:23 PM Page 53
  • 56.
    54 PREGUNTAS TEÓRICAS 1 ¿Cuáles, en el desarrollo web, el principal problema con el que se encuentra un desa- rrollador al recibir el trabajo del diseñador para ser implementado? 2 ¿Por qué es importante poner esfuerzo en el área de experiencia visual del usuario? 3 ¿Qué herramientas intentan unir el diseño y el desarrollo de software? 4 ¿Por qué es importante la creación de proto- tipos visuales en el desarrollo de software? 5 ¿Podemos encontrar todos los controles y componentes HTML representados en Sil- verlight con XAML? 6 ¿Qué tipos de proyectos es posible crear con Expression Blend 2? 7 ¿Es necesario instalar algún programa adi- cional para poder desarrollar aplicaciones Silverlight 2 con Expression Blend 2? 8 Si queremos ver todos los controles de Ex- pression Blend 2, ¿cómo accedemos a ellos? 9 ¿Es necesario contar con un servidor web para depurar las aplicaciones Silverlight desde Expression Blend 2? 10 ¿Cuántos tipos de controles encontramos en Silverlight? ¿Cómo los categorizamos? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Ingrese y navegue por Quince (http:// quince.infragistics.com), el sitio web de Infragistics dedicado a la mejora de las in- terfaces visuales. 2 Diríjase al sitio web oficial de Silverlight (http://silverlight.net) para ver más ejem- plos sobre esta plataforma. 3 Intente crear un visor de videos por Inter- net, ejecutando la aplicación creada me- diante el uso de IIS (Internet Information Services). 4 Ingrese en www.microsoft.com/surface, el sitio web de Microsoft Surface, para ver buenos ejemplos de interfaces visuales y su aplicación en soluciones de software. 5 Visite el sitio de experiencia para el usua- rio de Microsoft (www.microsoft.com/ design) para maximizar el conocimiento sobre posibilidades involucradas en esta área de la ingeniería de software. 02_Silverlight.qxp 9/30/09 1:23 PM Page 54
  • 57.
    El mejor trabajo, conla mejor herramienta Silverlight para desarrolladores 56 Puesta a punto de Visual Studio 2008 56 Silverlight 2 con Visual Studio 59 Crear la primera aplicación con Visual Studio 2008 63 Interoperabilidad con Expression Blend 2 76 Resumen 79 Actividades 80 Capítulo 3 Más allá de nuestro conocimiento, la forma más eficiente de crear viene de la mano de la mejor herramienta disponible. Así como los diseñadores visuales tienen una herramienta creada para ellos, los desarrolladores no se pueden quedar atrás. Visual Studio 2008 y Silverlight son una mezcla con la que podremos obtener código de extrema calidad. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 03_Silverlight.qxp 9/30/09 1:29 PM Page 55
  • 58.
    SILVERLIGHT PARA DESARROLLADORES Eneste punto, ya hemos pasado por los conceptos iniciales de Silverlight y recorri- mos un poco una de las herramientas provistas por Microsoft, Expression Blend 2, para desarrollar aplicaciones para esta plataforma. En este capítulo, hablaremos de Visual Studio 2008 como la herramienta ideal para los desarrolladores de software y también para desarrollar aplicaciones Silverlight. Además, crearemos una nueva aplicación que consuma datos y se los mostraremos al usuario. Puesta a punto de Visual Studio 2008 En el primer capítulo, comentamos que la versión 2 de Silverlight no viene incluida en Visual Studio 2008 y, por consiguiente, es necesario que hagamos esta instala- ción descargando los componentes desde la página de Microsoft. El motivo de es- ta sección en este capítulo se debe a que, en muchas ocasiones, nos encontramos con el dilema de no saber qué versión, componente u herramienta descargar. En general, los sitios de los proveedores suelen presentarnos más de una versión dis- ponible para su descarga, pero si elegimos una incorrecta nos retrasará en nuestro trabajo, así como también podemos encontrarnos con algún funcionamiento ines- perado mientras realizamos nuestro trabajo. En la Figura 1, se ilustra el sitio web de Microsoft que representa el portal de entrada para Silverlight. Figura 1. Portal de Silverlight en Microsoft.com. En esta figura, se muestra una lista de componentes que pueden ser descargados. El primero hace referencia al motor o plugin de Silverlight. Este motor es el que 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 56 03_Silverlight.qxp 9/30/09 1:29 PM Page 56
  • 59.
    debe instalar todousuario que quiera ver las aplicaciones Silverlight desde el na- vegador. Por supuesto, no es necesario que proveamos por nuestra cuenta este plugin ni que tengamos que instalarlo de forma manual en cada uno de los equi- pos y de los navegadores que quieran nuestro producto ya que, en la declaración del objeto Silverlight en el código HTML, se incluye una comprobación de ver- siones, además de indicarle al navegador de dónde obtener esta versión: object data=”data:application/x-silverlight,” type=”application/x- silverlight-2” width=”100%” height=”100%” param name=”source” value=”SilverlightApplication1.xap”/ param name=”onerror” value=”onSilverlightError” / param name=”background” value=”white” / param name=”minRuntimeVersion” value=”2.0.31005.0” / param name=”autoUpgrade” value=”true” / a href=”http://go.microsoft.com/fwlink/?LinkID=124807” style=”text- decoration: none;” img src=”http://go.microsoft.com/fwlink/?LinkId=108181” alt=”Get Microsoft Silverlight” style=”border-style: none”/ /a /object Este código es el que deberemos usar de manera habitual para la incrustación de aplicaciones Silverlight en páginas webs. Si analizamos las partes del código, ve- mos que, dentro del atributo data, se detalla el tipo de componente por ejecutar. De esta forma, el navegador sabrá que el objeto requerido es del tipo Silverlight. El atributo type específica la versión de aplicación que se usará, en nuestro caso, Silverlight 2. Los elementos param, con sus atributos name, preconfiguran la aplica- ción Silverlight. La propiedad onerror especifica el nombre de la función JavaScript que se ejecutará si ocurriera un error en el transcurso del implemento de la apli- cación. Por su parte, minRuntimeVersion detalla la versión exacta de la aplicación, por lo que deberemos tener el plugin compatible para poder ejecutarla. Silverlight para desarrolladores 57 , Este software no es un componente para realizar presentaciones vistosas en Internet. Por el con- trario, Silverlight no sólo cumple con esta característica, sino que extiende el desarrollo de apli- caciones profesionales al ambiente web con contenido dinámico. Podemos usar Silverlight, en especial, cuando tengamos que resolver problemas complejos desde la Web. ¿QUÉ ES SILVERLIGHT EN REALIDAD? 03_Silverlight.qxp 9/30/09 1:29 PM Page 57
  • 60.
    El parámetro autoUpgraderepresenta la capacidad del navegador para descargar en forma automática alguna nueva versión detectada, previa autorización del usuario. Por último, si el navegador no cuenta con la versión indicada o simplemente no tie- ne el plugin instalado, la página mostrará la imagen de la figura siguiente, con un vínculo a la versión descargable del plugin. Figura 2. Al no tener el plugin instalado, el usuario verá la imagen que le sugiere descargar el complemento. El segundo elemento de la lista de la Figura 1 representa todas las herramientas y SDKs (Software Development Kits o, en castellano, Grupo de herramientas para desarrollo). Necesitaremos descargar e instalar este conjunto de herramientas só- lo si ya contamos con las plantillas y actualizaciones de Visual Studio 2008. El tercer elemento es el más completo, ya que involucra el SDK y, además, incluye las actualizaciones para Visual Studio 2008, así como las plantillas necesarias para el desarrollo de aplicaciones Silverlight. En forma independiente del ele- mento elegido, la descarga y su posterior instalación siguen el patrón de cualquier aplicación bajo Windows. Basta con seguir los pasos provistos por el asistente para lograr una correcta instalación. Podremos comprobar que las herramientas se han instalado de manera correcta creando un nuevo proyecto desde Visual Studio 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 58 , Al momento de escribir este libro, se realizó el anuncio por parte de Microsoft de la nueva versión de Silverlight: Silverlight 3, versión que se encuentra en etapa beta. Si instalamos esta versión, no podremos seguir trabajando con la 2, que es la utilizada en este libro. Es re- comendable usar máquinas virtuales para instalar versiones beta. NUEVAS VERSIONES DE SILVERLIGHT 03_Silverlight.qxp 9/30/09 1:29 PM Page 58
  • 61.
    2008. Al crearel nuevo proyecto (menú Archivo/Nuevo/Proyecto…), deberemos tener la capacidad de ver el submenú relacionado con Silverlight en el árbol de tipos de proyectos, dentro del lenguaje de programación elegido. Al seleccionarlo, se verán las plantillas como se muestran en la siguiente figura. Figura 3. Silverlight con C#. Al crear un proyecto, vemos plantillas de Silverlight. Silverlight 2 con Visual Studio Si en el capítulo anterior identificamos a Expression Blend 2 como la herramienta ideal para el diseñador gráfico y para crear interfaces visuales en aplicaciones de software, podemos decir que Visual Studio 2008 es la ideal para los desarrolladores de software. En este grupo se incluyen tanto los programadores o codificadores, como los arquitectos de software, aseguradores de la calidad del producto y otros relacionados con la generación de la pieza de software. Esto quiere decir que, con Visual Studio 2008, nos focalizaremos en las líneas de código, por lo que el trabajo realizado sobre las aplicaciones estará planteado desde esta óptica y no relacionado en forma directa con la interfaz propiamente dicha. Silverlight para desarrolladores 59 RRR Es posible traducir a Interfaz de usuario el nombre que comúnmente podremos encontrar en ingeniería informática y que hace referencia a UI (User Interface en inglés). Este término se refiere a los componentes visuales involucrados en el software y que se relacionarán con el usuario que lo utilice. EL NOMBRE DE LA INTERFAZ DE USUARIO 03_Silverlight.qxp 9/30/09 1:29 PM Page 59
  • 62.
    Figura 4. Lacaja de herramientas de Visual Studio 2008. De todas maneras, si bien es posible utilizar esta herramienta para realizar todo el proceso, al mismo tiempo el desarrollador no debe olvidar la interfaz visual, ya que su código tendrá que adaptarse a las necesidades que se pudieran plantear tanto por el usuario como por el diseñador. Como dijimos en capítulos anteriores, siempre se- rá preferible, dentro del grupo de desarrollo o producción de software, contar con las habilidades y roles necesarios para generar el producto, dejando que cada uno, desde su rol y experiencia, realice el trabajo designado. Entonces, hacer uso de las dos herramientas, Visual Studio 2008 y Expression Blend 2, creará un ambiente de de- sarrollo ideal, porque tiene en cuenta los roles involucrados y preocupados por satis- facer las necesidades de sus áreas de interés, las cuales representan, en cierta medida, las necesidades del cliente. Como resultado, se obtendrá una mejor experiencia por cada una de las partes involucradas, ya que cada una estará enfocada en resolver el dominio de su problema y no, el de otros. Con esto queremos destacar que, si bien el desarrollador se encarga de la lógica y del código, no debería olvidar lo relaciona- do con interfaces gráficas, por lo que tener conocimientos de Expression Blend 2, aunque sea en menor medida que de Visual Studio 2008, le otorgará mayor criterio a la hora de entender e implementar lo que el diseñador gráfico le proporcione. Con Visual Studio 2008, no sólo podremos crear aplicaciones Silverlight, sino que además nos es posible enriquecerlas desde el punto de vista del código. En la barra de herramientas, notaremos que existen controles y componentes que no son mos- trados en Expression Blend 2. Esto se debe a que los componentes, como Calendar, DataGrid o DatePicker, son ideales para la interacción con datos y sólo se muestran desde el inicio para los desarrolladores, aunque no para los diseñadores, lo que no significa que no podamos utilizarlos desde Expression Blend 2. Si exploramos con mayor profundidad dentro de las aplicaciones Silverlight creadas desde Visual 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 60 03_Silverlight.qxp 9/30/09 1:29 PM Page 60
  • 63.
    Studio 2008, notaremosque, como todo desarrollo profesional de software, es posible agregar diferentes capas o niveles de código a esta aplicación. Se podrá, por ejemplo, consumir información desde un servicio web remoto y desplegar estos datos a los usuarios. Hablaremos más de este tema en el capítulo 7. Figura 5. Agregado de una referencia web a nuestra aplicación Silverlight. Otra de las cualidades más interesantes las presenta el asistente de escritura de có- digo IntelliSense, que se usa, en especial, para la escritura de código manejado (C#, Visual Basic.Net, etcétera), pero en este caso con soporte total para XAML, para acelerar la producción de estas líneas de código. Figura 6. IntelliSense para XAML, mostrando las propiedades disponibles de un componente TextBlock. Silverlight para desarrolladores 61 03_Silverlight.qxp 9/30/09 1:29 PM Page 61
  • 64.
    Por último, unade las capacidades más importantes que tiene Visual Studio 2008 cuando trabajamos con aplicaciones Silverlight es la depuración de código en tiempo de ejecución. Con esta característica, heredada del desarrollo tradicional de aplicaciones, podremos colocar puntos de interrupción en nuestro código y movernos línea a línea una vez que la aplicación esté trabajando. La ventaja de esta posibilidad radica en que, si encontramos un error en tiempo de ejecución de nuestra aplicación, podremos depurarla paso a paso para hallar el problema. Esto resultaría en extremo complicado si tuviéramos que hacer el trabajo mediante la inspección de las líneas y el cálculo de los estados de las variables y objetos en cada paso. Para lograrlo, podremos agregar un punto de interrupción con un clic del mouse en la parte extrema izquierda de nuestro código por cada línea en la que queramos que la ejecución se detenga. Figura 7. Algunos puntos de interrupción en nuestro código. Cuando ejecutamos nuestra aplicación Silverlight, notaremos que la ejecución del código se detiene en cada uno de los puntos de interrupción declarados, don- de podemos inspeccionar las variables y objetos en el estado que se encuentren 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 62 RRR Si no se encuentra visible la barra de herramientas de Visual Studio 2008, podemos hacerla aparecer con la combinación de teclas CTRL+ALT+X, dependiendo del tipo de configuración que hayamos elegido inicialmente, o si no, desde el menú Ver/Caja de Herramientas. BARRA DE HERRAMIENTAS EN VISUAL STUDIO 2008 03_Silverlight.qxp 9/30/09 1:29 PM Page 62
  • 65.
    en ese momento.En la figura que aparece a continuación, se muestra cómo el código se detiene, y uno de los objetos es inspeccionado. Figura 8. El código es detenido para evaluar el estado de los objetos. Microsoft Visual Studio 2008 no es sólo una potente herramienta para el desa- rrollo de software convencional, sino que, además, todas sus prestaciones pue- den ser usadas para el desarrollo de aplicaciones Silverlight. Por esto, así como el diseñador visual encuentra su lugar en Expression Blend 2, los desarrolladores de código lo harán en Visual Studio 2008. Crear la primera aplicación con Visual Studio 2008 En el capítulo anterior, pudimos crear un reproductor de videos con Expression Blend 2 y Silverlight. En este caso, y conociendo más a fondo las prestaciones de Visual Studio 2008, crearemos otra aplicación Silverlight, pero con el enfoque en la manipulación de datos. Para este caso, haremos un buscador de productos, con controles que ac- tuarán de filtro de búsqueda y una lista de registros o grilla que muestre los resultados encontrados. En este ejemplo, también usaremos LinQ para realizar consultas sobre objetos, características que trataremos con mayor profundidad en el capítulo 7. Como primer paso, es necesario crear una nueva aplicación Silverlight 2 desde Visual Studio 2008. Esto lo logramos desde al menú Archivo y, luego, Nuevo proyecto. En el árbol de soluciones, debemos buscar la opción de proyectos Silverlight para ver las plantillas de este tipo de proyectos. Una vez seleccionado el lenguaje de programación que usaremos, nos posicionamos sobre el tipo de proyecto Silverlight donde podre- mos ver las plantillas disponibles. En este caso, seleccionaremos la plantilla Aplicación de Silverlight para poder probar directamente nuestro proyecto; para ello, utilizaremos Silverlight para desarrolladores 63 03_Silverlight.qxp 9/30/09 1:29 PM Page 63
  • 66.
    alguna aplicación ASP.netexistente o crearemos una página de prueba para nues- tra aplicación. Si no vemos las plantillas Silverlight disponibles, usamos Visual Studio 2008 o superior y ya hemos instalado los aditamentos mencionados en el capítulo 1, es necesario asegurarnos de haber seleccionado la versión correcta de Microsoft .Net Framework desde la lista desplegable en la parte superior dere- cha del asistente para creación de proyectos, como podemos ver a continuación. Figura 9. Es importante seleccionar la versión 3.5 de Microsoft .Net Framework para poder ver las plantillas de Silverlight. Una vez cumplidos los pasos anteriores, Visual Studio nos preguntará sobre la modalidad que utilizaremos para depurar la aplicación Silverlight, y nos permi- tirá elegir entre las siguientes opciones: • Crear un nuevo proyecto ASP.net: esta opción agregará un proyecto adicional del tipo ASP.net a la solución e incrustará, de manera automática, nuestro proyecto Silverlight a la página por defecto. Cuando depuremos la solución, Visual Studio abrirá la página ASP.net para mostrar el componente Silverlight creado por nosotros. 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 64 RRR En varias ocasiones, hablaremos de tiempos de ejecución y tiempo de compilación. Tiempo de compilación hace referencia al momento en el que nuestro código es transformado en un ejecuta- ble. Tiempo de ejecución alude, en cambio, al momento en que nuestro código se ejecuta. TIEMPO DE EJECUCIÓN 03_Silverlight.qxp 9/30/09 1:29 PM Page 64
  • 67.
    • Generación automáticade una página: en este caso, Visual Studio no creará nin- guna página ni proyecto adicional a la solución y sólo veremos el proyecto Silverlight en el cual trabajaremos. Cuando intentemos depurar la aplicación Sil- verlight, Visual Studio creará una página de manera dinámica en la que podremos ver y probar el funcionamiento de nuestro componente Silverlight. • Vincular el control Silverlight: si ya contamos con un sitio web previamen- te creado, podremos usar esta opción para vincular el proyecto Silverlight con aquél y depurarlo basado en esta implementación existente. Deberemos selec- cionar esta opción cuando queramos trabajar en forma directa sobre nuestras implementaciones web y hacer interactuar nuestro proyecto Silverlight con el ambiente real donde será desplegado. Figura 10. En la imagen, vemos las tres opciones disponibles para crear nuestra aplicación Silverlight. Para este ejemplo, seleccionaremos la segunda opción, ya que no necesitaremos in- teractuar con nuestra aplicación Silverlight de manera externa o desde el navegador del cliente. Una vez creado el proyecto, Visual Studio 2008 nos presentará el lienzo Silverlight para desarrolladores 65 RRR La lista de lenguajes disponibles en Visual Studio varía sobre la base de los que hayamos insta- lado junto con la herramienta. En una instalación típica, podremos elegir entre Visual C++, C#, Visual Basic.net y J#. Para poder usar lenguajes de otros fabricantes, deberemos adquirirlos desde sus respectivas páginas webs. LENGUAJES DISPONIBLES 03_Silverlight.qxp 9/30/09 1:29 PM Page 65
  • 68.
    de dibujo deSilverlight y, en la misma pantalla, el código XAML que representa este lienzo. Al igual que Expression Blend 2, el código inicial se ve como sigue: UserControl x:Class=”SilverlightApplication1.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=”Layout” Background=”White” /Grid /UserControl La principal desventaja que presenta trabajar con Visual Studio 2008 es que no po- dremos modificar el lienzo directamente, como en el caso de Expression Blend 2, sino que deberemos trabajar todo desde el código XAML, lo que requerirá de no- sotros mayor dominio de éste para conseguir el resultado final. Figura 11. Vista inicial de una aplicación Silverlight creada con Visual Studio 2008. 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 66 _` Visual Studio 2008 tiene la particularidad de soportar el desarrollo para diferentes versiones de .Net Framework. Gracias a ello, se convierte en una herramienta versátil, que permite editar proyectos creados en versiones anteriores de Visual Studio así como crear proyectos para ver- siones previas a la última versión del Framework. VISUAL STUDIO Y LAS VERSIONES DE .NET FRAMEWORK 03_Silverlight.qxp 9/30/09 1:29 PM Page 66
  • 69.
    En este ejemplo,haremos uso del contenedor Grid para agrupar y ordenar nuestros elementos. Por un lado, necesitaremos alguna forma de permitir que el usuario escriba lo que quiere buscar, capturando dicha entrada y proporcionando la posi- bilidad de activar la búsqueda. Esto podemos conseguirlo mediante un compo- nente TextBox y un componente Button. Estos controles deberemos alinearlos de tal manera que se vean uno al lado del otro. Para conseguir este efecto, agregaremos un par de filas y de columnas al contenedor Grid inicial de la siguiente manera: Grid x:Name=”Layout” Background=”White” Grid.RowDefinitions RowDefinition Height=”40”/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions /Grid El tag Grid.RowDefinitions deberemos utilizarlo para agrupar la cantidad de filas que contendrá esta grilla; cada elemento RowDefinition representará específica- mente una fila de la grilla, pudiendo definir por cada una sus dimensiones. Por otro lado, el tag Grid.ColumnDefinitions representa la colección de columnas que con- tendrá la grilla, pudiendo definir elementos ColumnDefinition dentro de ésta, los que especificarán cada una de las columnas por visualizar. La grilla definida sólo ser- virá como organizador de los demás controles y componentes y no para mostrar los datos propiamente dichos. El siguiente paso consiste en agregar un TextBox y un bo- tón, los que ubicaremos en la primera fila, y primera y segunda columna de nues- tra grilla. Podemos ver el resultado en el siguiente código: Silverlight para desarrolladores 67 RRR En los capítulos se hace referencia a controles y componentes. Éstos deben ser entendidos como piezas de software, código funcional encapsulado para su posterior reutilización. Los controles suelen tener comportamiento visual mientras que los componentes, no. CONTROLES Y COMPONENTES 03_Silverlight.qxp 9/30/09 1:29 PM Page 67
  • 70.
    TextBox Grid.Row=”0” Grid.Column=”0” x:Name=”txtBusqueda”Margin=”5,5,5,5”/TextBox Button Grid.Row=”0” Grid.Column=”1” Width=”100” HorizontalAlignment=”Right” Margin=”0,5,5,5” Content=”Buscar”/Button Para ubicar los componentes en el área de la grilla, es necesario determinarlo en el mis- mo control y no, como podríamos estar acostumbrados en HTML o lenguajes simila- res, dentro de la definición de la fila y la columna. Por este motivo, haremos uso del atributo Grid.Row y Grid.Column para determinar la celda en la cual se visualizará el con- trol. La colección de filas y de columnas se representa mediante un índice con base 0 por lo que, si hacemos referencia a la primera fila y a la primera columna, tendremos que usar el 0 (cero) en ambos casos. Otros de los atributos que podemos observar es el de x:Name para el componente TextBox. Con él, accederemos a la información escrita por el usuario para hacer la búsqueda respectiva; el atributo Margin nos permite agre- gar al control márgenes en pixeles para que no cubra la totalidad de la celda (es posi- ble asignarles márgenes izquierdos, superiores, derechos e inferiores, en ese orden, se- parados por comas). En el caso del botón, el atributo Content representa el texto por mostrar dentro del componente. En el siguiente paso agregaremos una grilla con ca- pacidades de manipulación de datos. Para esto, deberemos seleccionarla y arrastrarla desde la barra de herramientas de Visual Studio. Al hacerlo, veremos que, además del código XAML, también se adicionará una nueva referencia a nuestro proyecto. Esta re- ferencia es System.Windows.Controls.Data y es necesaria para utilizar aquellos compo- nentes con soporte de enlazado de datos, en este caso el control DataGrid. Figura 12. Si arrastramos y soltamos un DataGrid a nuestro proyecto, accederemos a un control listo para usar con la capacidad de desplegar registros. 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 68 03_Silverlight.qxp 9/30/09 1:29 PM Page 68
  • 71.
    Este DataGrid tambiénnecesitará ser asignado a una fila y a una columna dentro de la grilla general, de la siguiente manera: data:DataGrid Grid.Row=”1” Grid.Column=”0” x:Name=”GrillaDeProductos” Grid.ColumnSpan=”2” AutoGenerateColumns=”True” /data:DataGrid Figura 13. Lista de referencias en nuestro proyecto, incluyendo System.Windows.Controls.Data para el manejo del DataGrid. Una vez más, los atributos Grid.Row y Grid.Column son utilizados para posicio- nar este componente en una de las celdas de la grilla, aunque en este caso apa- rece un nuevo atributo llamado Grid.ColumnSpan. Este atributo es necesario para decirle al DataGrid que debe emplear u ocupar las dos columnas de la fila en la cual se encuentra. Si obviáramos este parámetro, obtendríamos un resultado no deseado, como podemos ver en la figura de la siguiente página. Silverlight para desarrolladores 69 RRR Como estamos trabajando con la última versión del lenguaje C#, encontraremos mejoras que facilitarán la rápida escritura del código. En la versión 2008 del lenguaje, no se requiere que escribamos el contenido de los get y set en las propiedades y sus respectivas variables privadas, ya que lo hará por nosotros cuando se genere el programa. NUEVO C# 03_Silverlight.qxp 9/30/09 1:29 PM Page 69
  • 72.
    Figura 14. Alno especificar cuántas columnas ocupará el DataGrid, éste sólo se enfoca en la primera, dando un aspecto no deseado para este caso. Otro atributo nuevo que aparece es el AutoGenerateColumns, que especifica que las columnas del DataGrid se crearán por cuenta propia sobre la base de la infor- mación enviada, por lo que, si nuestra colección de datos posee N columnas, éstas serán representadas por el componente. En este punto, ya tenemos toda la interfaz visual creada, por lo tanto, pasaremos a crear el código C# que realice las búsquedas basadas en la entrada del usuario. Sobre el proyecto, agregaremos una nueva clase C# (productos.cs) que usaremos como entidad contenedora de datos. Esto podemos lograrlo por medio de un clic con el botón secundario del mouse sobre el proyecto Silverlight y con la adición de un nuevo ítem. En el asistente, seleccionaremos la opción de código y, a continuación, la plantilla para nuevas clases. Esta clase debe contener la descripción de todos los campos que necesitaremos desplegar o por los que realizaremos búsquedas en nuestro código. Al tratarse de la representación de productos, ésta podría contener algunas propiedades como iden- tificador del producto, nombre del producto, descripción, precio, cantidad en stock y otras que se adecuen al negocio. La clase producto debería quedar como sigue: 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 70 RRR Intellisense resulta extremadamente útil para completar código. Desde Visual Studio podemos activarlo con la combinación CTRL+J. En el desarrollo de aplicaciones Silverlight no sólo es posible usar Intellisense en código C#, también está disponible para código XAML. MICROSOFT INTELLISENSE 03_Silverlight.qxp 9/30/09 1:29 PM Page 70
  • 73.
    public class producto { publiclong ID_Producto { get; set; } public string Nombre { get; set; } public string Descripcion { get; set; } public decimal Precio { get; set; } public int Stock { get; set; } } El siguiente paso es enlazar el evento click del botón a nuestro código C#. Podemos hacerlo con facilidad desde el código XAML de nuestra aplicación, si escribimos el nombre del evento en el botón y dejamos que Visual Studio complete el código cuando presionamos la tecla TAB, como podemos ver en la siguiente figura. Silverlight para desarrolladores 71 03_Silverlight.qxp 9/30/09 1:29 PM Page 71
  • 74.
    Una vez generadoel evento, el código XAML se verá de la siguiente manera: Button Grid.Row=”0” Grid.Column=”1” Width=”100” HorizontalAlignment=”Right” Margin=”0,5,5,5” Content=”Buscar” x:Name=”Button1” Click=”Button1_Click”/Button Y el código C# de nuestra aplicación tendrá el siguiente aspecto: public partial class Page : UserControl { public Page() { InitializeComponent(); } private void Button1_Click(object sender, RoutedEventArgs e) { } } La función Button1_Click se ejecutará cada vez que el usuario presione el botón en la interfaz. Por tal motivo, deberemos agregar la lógica de búsqueda dentro de esta función. Pero, antes de realizar esta lógica, es necesario contar con los da- tos sobre los cuales trabajaremos. Para esto, crearemos una lista genérica de pro- ductos y la cargaremos con datos suficientes para poder hacer búsquedas sobre ellos. La carga de la lista podremos dispararla desde una función privada que se- rá llamada una única vez cuando la aplicación se cargue en primera instancia. Es- to podemos lograrlo llamando el llenado de la lista desde la función Page en nues- tro código similar al siguiente: 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 72 RRR Todos los controles en Silverlight poseen una serie de eventos. Estos eventos representan si- mulaciones de acciones reales en la interfaz gráfica. El clic del ratón, una tecla presionada, el conteo de un reloj son reacciones a cuestiones cotidianas de las aplicaciones. A estas reaccio- nes, las llamamos eventos. EVENTOS 03_Silverlight.qxp 9/30/09 1:29 PM Page 72
  • 75.
    public Page() { InitializeComponent(); CargarLista(); } private Listproductoproductos; private void CargarLista() { //Inicializamos la lista de productos productos = new Listproducto(); //Cargamos la lista de productos con productos productos.Add(new producto() { ID_Producto = 1, Nombre = “PC Básica”, Descripcion = “PC de escritorio básica”, Precio = 1500, Stock = 10 }); productos.Add(new producto() { ID_Producto = 2, Nombre = “PC Superior”, Descripcion = “PC de escritorio superior”, Precio = 3500, Stock = 50 }); productos.Add(new producto() { ID_Producto = 3, Nombre = “PC Notebook”, Descripcion = “PC tipo Notebook”, Precio = 2500, Stock = 40 }); Silverlight para desarrolladores 73 03_Silverlight.qxp 9/30/09 1:29 PM Page 73
  • 76.
    productos.Add(new producto() { ID_Producto =4, Nombre = “PC NetBook”, Descripcion = “PC tipo NetBook”, Precio = 2000, Stock = 450 }); productos.Add(new producto() { ID_Producto = 5, Nombre = “SmartPhone”, Descripcion = “Teléfono SmartPhone”, Precio = 500, Stock = 55 }); } Una vez cargados los elementos en la lista, sólo nos queda realizar la búsqueda sobre la base de las entradas del usuario. Para acelerar las consultas, usaremos LinQ sobre colecciones. La función enlazada al evento click del botón deberá tener un aspecto similar al siguiente: private void Button1_Click(object sender, RoutedEventArgs e) { IEnumerableproducto q = from c in productos where c.Nombre.Contains(this.txtBusqueda.Text) || c.Descripcion.Contains(this.txtBusqueda.Text) select c; this.GrillaDeProductos.ItemsSource = q; } Si usamos la lista genérica productos, realizamos una consulta donde la cláusula where restringe la búsqueda a todos los registros donde el nombre o la descrip- ción del producto concuerden con lo introducido por el usuario, en su totalidad o sólo en una parte. El equivalente a esto en T-SQL sería mediante el uso de: Nombre like %DATO DEL USUARIO% OR Descripcion like %DATO DEL USUARIO%. 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 74 03_Silverlight.qxp 9/30/09 1:29 PM Page 74
  • 77.
    Por último, seleccionamoslos valores resultantes de la búsqueda y se le asignan a la variable q, que será asignada a la propiedad ItemsSource del DataGrid para que lo tome como su fuente de datos. Figura 15. Nuestra aplicación muestra los datos filtrados por la palabra clave introducida por el usuario. Podemos extender la funcionalidad de nuestra aplicación y del componente DataGrid si agregamos algunas propiedades. Este control es lo suficientemente versátil como pa- ra permitir modificar su apariencia y su comportamiento. A continuación, agregamos la capacidad de que el usuario pueda reordenar las columnas de la grilla de resultados, y además le asignamos colores al fondo de cada uno de los ítems desplegados: data:DataGrid Grid.Row=”1” Grid.Column=”0” x:Name=”GrillaDeProductos” Grid.ColumnSpan=”2” AutoGenerateColumns=”True” CanUserReorderColumns=”True” CanUserResizeColumns=”False” AlternatingRowBackground=”LightBlue” RowBackground=”LightGreen” /data:DataGrid Las propiedades CanUserReorderColumns y CanUserResizeColumns permiten que el usuario mezcle las columnas arrastrándolas y soltándolas, y que pueda o no re- dimensionar el tamaño de las columnas. Para especificar los colores de las filas, usamos RowBackground, que asignará el color de fondo para la fila, y Alternating RowBackground, que configurará el color de fondo de las filas alternativas (por cada fila par, usará este color en lugar del configurado en RowBackground). Silverlight para desarrolladores 75 03_Silverlight.qxp 9/30/09 1:29 PM Page 75
  • 78.
    Figura 16. Laimagen muestra cómo el usuario puede reordenar las columnas una vez activada la propiedad. Interoperabilidad con Expression Blend 2 Si bien dijimos que el desarrollador de software debe enfocarse en las líneas de códi- go y en la resolución del dominio del problema, existirán oportunidades en las que necesite hacer modificaciones en la interfaz visual o, en casos extremos, crearla por su cuenta. En este capítulo, pudimos ver que Visual Studio 2008 por sí solo no resulta tan versátil como es necesario en cuanto a diseño visual de aplicaciones Silverlight. Só- lo tenemos una vista previa de lo que diseñamos en XAML, por lo que nos demanda un conocimiento avanzado sobre la descripción de cada control y cada componente, sus jerarquías, atributos y composiciones. Esto, hasta no conseguir suficiente expe- riencia, podría transformarse en una situación un tanto frustrante. Por ello, es reco- mendable tener instaladas las dos herramientas, aunque sólo nos dediquemos a una de las ramas del desarrollo del producto. Si lo hacemos, podremos abrir el proyecto en el que estemos trabajando con Expression Blend 2 para su edición sin la necesidad de cerrar la solución o abrirla de manera externa. Si queremos editar nuestro proyecto 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 76 RRR Es recomendable que siempre tengamos instalado Expression Blend 2 en nuestro equipo cuando desarrollemos aplicaciones Silverlight. Sin importar si sólo nos dedicamos a la producción de código, esta herramienta nos ayudará a acelerar la producción de código XAML y nos facilitará la creación de contenido visual. EXPRESSION BLEND 2 03_Silverlight.qxp 9/30/09 1:29 PM Page 76
  • 79.
    con Expression Blend2, lo único que necesitamos es seleccionar la página XAML por editar y, con el botón secundario del mouse, pulsar Abrir en Expression Blend…. Figura 17. Con el botón secundario del ratón, es posible abrir nuestro proyecto en Expression Blend 2. Expression Blend 2 cargará el proyecto representándolo en su árbol de soluciones. Las modificaciones que hagamos en esta solución se verán reflejadas, de forma automática, en Visual Studio 2008. En la figura siguiente, se observa, a la derecha, el árbol de la so- lución y, a la izquierda, la lista de controles presentes en el proyecto. Editar las propie- dades visuales puede resultar más simple desde aquí que desde Visual Studio 2008. Figura 18. A la derecha, el árbol de la solución representado de igual manera que en Visual Studio 2008. Silverlight para desarrolladores 77 03_Silverlight.qxp 9/30/09 1:29 PM Page 77
  • 80.
    Para completar elejemplo, modificaremos la apariencia del componente DataGrid. Primero lo seleccionamos en la lista de controles y luego, en la pestaña Propiedades, modificamos los colores usados para cada uno de los registros, así como el fondo. Figura 19. Una vez que seleccionamos el DataGrid, modificamos sus propiedades en la pestaña Propiedades. Podríamos ejecutar la aplicación desde Expression Blend 2 para ver sus resultados, aunque en este caso, una vez guardados los cambios, cerraremos esta aplicación y vol- veremos a Visual Studio 2008. Si éste ha detectado cambios en el XAML, nos pedirá autorización para recargar el contenido. En este caso, aceptaremos las modificaciones ya que representan los cambios realizados. Una vez que la aplicación haya sido recar- gada, depuramos el código presionando la tecla F5. Luego, si inspeccionamos el códi- go XAML del DataGrid generado por Expression Blend 2, notaremos cambios: data:DataGrid Grid.Row=”1” Grid.Column=”0” x:Name=”GrillaDeProductos” Grid.ColumnSpan=”2” AutoGenerateColumns=”True” CanUserReorderColumns=”True” CanUserResizeColumns=”False” data:DataGrid.Background LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FF462BEE”/ GradientStop Color=”#FFE1E0EA” Offset=”1”/ /LinearGradientBrush /data:DataGrid.Background data:DataGrid.RowBackground 3. EL MEJOR TRABAJO, CON LA MEJOR HERRAMIENTA 78 03_Silverlight.qxp 9/30/09 1:29 PM Page 78
  • 81.
    LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStopColor=”#FF92B6C7”/ GradientStop Color=”#FF51BFF0” Offset=”1”/ /LinearGradientBrush /data:DataGrid.RowBackground data:DataGrid.AlternatingRowBackground LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FF657446”/ GradientStop Color=”#FFE0F2BA” Offset=”1”/ /LinearGradientBrush /data:DataGrid.AlternatingRowBackground /data:DataGrid Figura 20. Nuevo aspecto visual del DataGrid basado en las modificaciones realizadas en Expression Blend 2. Silverlight para desarrolladores 79 … RESUMEN Visual Studio 2008 brinda al desarrollador elementos para acelerar la producción de código, así como también controles y componentes exclusivos para la resolución de problemas planteados en el proceso de producción del software. Visual Studio 2008 también deja modificar la parte visual con herramientas externas como Expression Blend 2. Demuestra así su versatilidad en el desarrollo de software y permite compartir visiones entre el productor de las interfaces gráficas y el desarrollador de funcionalidades. 03_Silverlight.qxp 9/30/09 1:29 PM Page 79
  • 82.
    80 PREGUNTAS TEÓRICAS 1 ¿Porqué es importante colocar la versión correcta de Silverlight en la declaración HTML del componente? 2 ¿Qué es un SDK? 3 ¿Es necesario instalar algún aditamento para Visual Studio 2008 antes de desarro- llar con Silverlight 2? 4 ¿Cuál es la diferencia entre Expression Blend 2 y Visual Studio 2008? 5 ¿Es posible adicionar referencias a servi- cios web en un proyecto Silverlight 2? 6 ¿Cómo se denomina el mecanismo que proporciona ayuda en el momento de la es- critura de código? 7 ¿Contamos, en Visual Studio 2008, con so- porte para escritura de código XAML? 8 ¿Entre qué opciones podremos elegir al crear un nuevo proyecto Silverlight 2? 9 ¿Qué ensamblado .Net se referencia en el momento en el que el control DataGrid es adicionado a nuestro proyecto Silverlight 2? 10¿Cuál es la diferencia entre usar la propie- dad AutoGenerateColumns y no usarla en el control DataGrid? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Para saber más sobre LinQ, ingrese en el sitio de MSDN (http://msdn.microsoft. com/es-es) y busque esta tecnología. 2 Para poner en práctica LinQ, trate de mo- dificar el ejemplo presentado en este capí- tulo incorporando el precio dentro de los parámetros del filtro de búsqueda. 3 Intente cambiar los colores utilizados pa- ra representar los elementos en el control DataGrid y, así, obtener un nuevo aspecto en la aplicación. 4 Si el código HTML presentado en este ca- pítulo le resultó extraño, visite el sitio web de la W3C para aprender más sobre esta tecnología: www.w3.org/html. 5 Revise la documentación sobre servicios web en la dirección http://msdn.microsoft. com/es-es para saber más sobre este tema. 03_Silverlight.qxp 9/30/09 1:29 PM Page 80
  • 83.
    XAML al extremo El lenguajeXAML 82 ¿Qué es XAML? 82 Declaración de objetos 82 Controles y componentes 83 Controles contenedores y agrupadores 84 Control Grid 84 Control GridSplitter 89 Control Canvas 92 Control StackPanel 95 Control ScrollViewer 98 Control Border 101 Controles de interacción con el usuario 103 Control Button 103 Control CheckBox 106 Control RadioButton 110 Control HyperlinkButton 113 Control Image 114 Control ComboBox 117 Control ListBox 124 Control TextBlock 126 Control TextBox 127 Control PasswordBox 130 Control DataGrid 132 Control Calendar 139 Control DatePicker 147 Control ProgressBar 148 Control Slider 152 Resumen 153 Actividades 154 Capítulo 4 Es necesario tener una referencia de cada uno de los controles y componentes propuestos por Silverlight. Cada uno de ellos, su declaración, métodos, eventos y uso serán tratados en este capítulo, que servirá como un manual que nos guiará y ayudará en la construcción de nuestras aplicaciones Silverlight. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 04_Silverlight.qxp 9/30/09 1:31 PM Page 81
  • 84.
    EL LENGUAJE XAML Hastaeste momento, ya hemos hablado de Silverlight, su arquitectura, alcances y restricciones. Hemos usado dos de las principales herramientas para desarrollar con Silverlight, así como realizado algunos ejemplos iniciales para poder mover- nos con mayor soltura, además de entender mejor esta tecnología. Es momento, entonces, de hacer un recorrido más exhaustivo sobre cada uno de los controles y componentes que podemos encontrar en Silverlight. En este capítulo, veremos ca- da uno de los elementos representados con XAML provistos por Silverlight, sus propiedades y sus usos elementales desde C#. Esta parte del libro puede ser con- siderada como una referencia a los controles de Silverlight y XAML. ¿Qué es XAML? XAML es un lenguaje declarativo que tiene su raíz en el XML. Con XAML, es posible declarar objetos que representen una interfaz gráfica común entre dife- rentes plataformas. Uno de los problemas acarreado por las plataformas, ya sean de escritorio, webs, u otras, así como distintos sistemas operativos, Windows, Linux, etcétera, consiste en la imposibilidad de compartir entre ellas los mismos ele- mentos visuales que componen la interfaz. Un acercamiento a esta solución es el HTML, aunque éste sólo es aplicado a la Web, y no se pueden compartir los mis- mos elementos en aplicaciones de escritorio. XAML, entonces, une bajo el mismo lenguaje declarativo la posibilidad de utilizar una única interfaz gráfica en diferen- tes ambientes. En el caso de aplicaciones de escritorio bajo Windows, mediante WPF, y, en la Web, por medio de Silverlight. Es necesario tener cierto cuidado cuando escribimos XAML, ya que éste es sensible a mayúsculas y minúsculas. Esto quiere decir que deberemos prestar mucha aten- ción cuando queramos usar cualquier control o componente en Silverlight, ya que un cambio de mayúsculas a de minúsculas hará que la aplicación deje de funcionar. Declaración de objetos Los objetos en XAML pueden ser declarados de diferentes formas. Pero, en cual- quier caso, un tag inicial deberá siempre ser cerrado al terminar de usarlo. Estos objetos suelen presentar dos formas tradicionales de declaración. Objeto /Objeto Es importante que notemos la diferencia entre el tag de apertura y el de cierre. Como vemos, para poder cerrar un objeto en XAML, es necesario utilizar los 4. XAML AL EXTREMO 82 04_Silverlight.qxp 9/30/09 1:31 PM Page 82
  • 85.
    caracteres /, porlo demás, el nombre del objeto de apertura y su sintaxis son idén- ticos. Esto quiere decir que se respetan las mayúsculas y minúsculas. También es posible, si el tag lo permite, su apertura y cierre en una sola línea. Objeto / En el caso anterior, el tag es abierto al comienzo y cerrado al final con los mis- mos caracteres (/). Por otro lado, al ser un lenguaje basado en XML, con nodos y subnodos, si el modelo de objeto lo permite es posible declarar un elemento dentro de otro, lo que permitirá crear elementos mucho más ricos. Esto adicio- nará, además, versatilidad y simpleza en el momento de tener que crear compo- nentes más complejos, como botones que presenten como fondo un video y no un color plano, o agregar casillas de verificación a una lista desplegable. Podemos anidar uno o más elementos de la siguiente forma. Canvas Button/Button /Canvas CONTROLES Y COMPONENTES A lo largo de los tres primeros capítulos, nos hemos encontrado con algunos de los controles y componentes disponibles en Silverlight: controles contenedores de otros controles; controles utilizados para mostrar videos, imágenes o datos; así como con- troles que capturan el comportamiento del usuario sirviéndonos de nexo entre éste y la aplicación creada. Este comportamiento es iniciado, por lo general, con la ayuda de un evento. Alguno de estos eventos son comunes a todos los controles Silverlight y entre ellos podemos encontrar los siguientes: Controles y componentes 83 _` Un intento de acercar la conmutación de la interfaz gráfica entre plataformas fue la creada por Microsoft por medio de los archivos HTA (HTML Application). Aquí, archivos con tags HTML re- gulares podían ser ejecutados en Windows sin la necesidad explícita de un navegador web. ARCHIVOS HTA 04_Silverlight.qxp 9/30/09 1:31 PM Page 83
  • 86.
    • GotFocus: esteevento se disparará cuando el control tome el foco de la acción. Pue- de ser usado cuando el usuario navega de un control a otro en nuestra aplicación Silverlight, pulsando la tecla TAB o presionando con el ratón. • IsEnabledChanged: si modificamos el estado del control, pasándolo de habilitado a no habilitado, este evento nos pondrá en alerta sobre ese cambio. • KeyDown: en este caso, si el usuario presiona una tecla cuando el control tiene el foco, el evento se disparará. • KeyUp: acción contraria a la anterior. Este evento se disparará en el momento en el que la tecla sea liberada. Esto es, cuando el usuario dejó de presionarla. • LayoutUpdated: cada vez que exista una modificación visual en el control, ya sea por adición de otro control, movimiento de las barras de desplazamiento o cam- bio de tamaño del control, este evento será disparado. • LostFocus: ésta es la acción opuesta a GotFocus. En el momento en que el con- trol pierda el foco, el evento nos pondrá en alerta. • SizeChanged: si el control se modifica en su tamaño, este evento lo comunicará. Es importante tener presente estos eventos, ya que nos serán de utilidad en la imple- mentación de nuestro código y en el comportamiento de la aplicación. Si bien algunos eventos son comunes a todos los controles, la declaración y el uso varían. Veamos entonces, uno a uno, los controles y lo componentes disponibles, su funcionalidad, su declaración sintáctica y cómo podemos interactuar con ellos desde nuestro código. Controles contenedores y agrupadores Los siguientes controles forman parte de los usados para agrupar o contener otros controles. Estos controles se utilizan, en especial, para manipular la estructura de diseño de nuestra aplicación. Con ellos, es posible colocar elementos en diferentes posiciones, mantenerlos en fijos o desplazarlos por la aplicación como un todo. Control Grid El control Grid, o grilla en castellano, está pensado para la representación de filas y columnas dentro del lienzo de dibujo de Silverlight. Debemos usar este control cuando necesitemos organizar, de forma estructurada, otros controles Silverlight, colocando dentro de cada celda de la grilla el o los controles adicionales. Pensemos en este control como si fuera una planilla de cálculo o, para aquellos desarrollado- res web, en el tag Table, con sus TR y TD usados en el HTML. La declaración inicial de un control Grid es simple: Grid x:Name=”[NombreDelControl]” /Grid 4. XAML AL EXTREMO 84 04_Silverlight.qxp 9/30/09 1:31 PM Page 84
  • 87.
    El tag Gridmarca el inicio del control Grid, y debe ser cerrado con su tag finalizador /Grid. Todos los controles contenidos por el elemento Grid deberán ser escritos en- tre estos dos tags. Es importante, pero no obligatorio, asignarle un nombre por medio del atributo x:Name al control Grid (deberemos hacerlo si necesitamos manipularlo en tiempo de ejecución). Tenemos que declarar las filas y las columnas al inicio de nues- tro control Grid, pudiendo especificar tantas filas y columnas como necesitemos: Grid x:Name=”[NombreDelControl]” Grid.RowDefinitions RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions /Grid El tag Grid.RowDefinitions es el contenedor de la cantidad de filas que incluirá el control, y debemos colocar dentro de los límites de éste tantos tags RowDefinition como filas queramos tener. Por su parte, el tag /Grid.RowDefinitions deberá in- cluirse para marcar el cierre y contenido de las filas definidas. De igual manera, el tag Grid.ColumnDefinitions tiene un comportamiento similar a Grid.RowDefinitions, con la clara diferencia que enumera las columnas del control Grid. Debemos colo- car tantos ColumnDefinition como columnas queramos tener en nuestra grilla. Al finalizar la lista, cerramos el tag por medio de /Grid.ColumnDefinitions. En el có- digo anterior, nuestra grilla cuenta con dos filas y tres columnas. Con la estructura básica de la grilla definida, es posible asignarles atributos a los tags para modificar su comportamiento. Los primeros atributos son los que especifican el ancho (Width) y el alto (Height), tanto sea de las columnas como de las filas: Controles y componentes 85 RRR Una celda, en un control del tipo Grid, se encuentra conformada por la unión de sus filas y de sus columnas. El resultado de unir estos dos elementos arrojará un espacio para colocar otros controles o una celda. Es necesario el par columna y fila para poder obtener esta celda. UNA CELDA 04_Silverlight.qxp 9/30/09 1:31 PM Page 85
  • 88.
    Grid.ColumnDefinitions ColumnDefinition Width=”60”/ ColumnDefinition Width=”50*”/ ColumnDefinitionWidth=”20”/ /Grid.ColumnDefinitions En la definición anterior, cada columna posee un ancho específico, cuyo valor es representado en pixeles. La segunda columna tiene un valor característico repre- sentado por un * (asterisco); este signo representa un comodín y significa que la columna ocupará los pixeles indicados anteriormente más todos los que se en- cuentran libres, no definidos por las demás columnas. Si tenemos una grilla que ocupa 400 pixeles de ancho, y contamos con una su- ma total de columnas, de acuerdo con el ejemplo anterior, de 130 pixeles, la se- gunda columna ocupará 50 pixeles más 270 pixeles restantes. Esta característica es importante cuando necesitamos mantener ciertas columnas estáticas y otras que se adapten sobre la base del ancho del contenedor de nuestra aplicación. Como ejemplo, podríamos incrustar una aplicación Silverlight, en una página web, que ocupe el 100% de su ancho. Esta página podría ser visitada por dife- rentes entornos con distintas resoluciones de pantalla, lo que haría que la pági- na se adaptase, en ancho, a la configuración del usuario, y lograría que nuestra aplicación Silverlight también se adaptara a ésta modificando dinámicamente las columnas que posean un asterisco. Podemos observar el resultado de las confi- guraciones de las columnas en la figura que vemos a continuación. Figura 1. En esta imagen, podemos ver un control Grid configurado usando Expression Blend 2. 4. XAML AL EXTREMO 86 04_Silverlight.qxp 9/30/09 1:31 PM Page 86
  • 89.
    Sobre las filas,es posible configurar el alto (Height) como en el siguiente código: Grid.RowDefinitions RowDefinition Height=”70*”/ RowDefinition Height=”70”/ /Grid.RowDefinitions Con características idénticas a las nombradas para las columnas, podremos usar el comodín * para modificar el alto de las filas de manera dinámica. Si no espe- cificamos un valor para el alto y el ancho a nivel del tag de la grilla, ésta asumirá que debe ocupar la totalidad definida por el contenedor. Podremos modificar es- tos valores agregando en forma manual estos valores: Grid x:Name=”[NombreDelControl]” Width=”200” Height=”200” Grid.RowDefinitions RowDefinition Height=”70*”/ RowDefinition Height=”70”/ ... ... Figura 2. Ancho y alto definidos usando Expression Blend 2. ShowGridLines, Cursor, ToolTipService.ToolTip son otros atributos que pueden ser usados a nivel del tag que representa la grilla. ShowGridLines puede contener dos valores: True (verdadero) o False (falso), y mostrar o no las líneas que definen el Controles y componentes 87 04_Silverlight.qxp 9/30/09 1:31 PM Page 87
  • 90.
    contorno de lagrilla, sus filas y columnas. Por su parte, Cursor configura el tipo de puntero de mouse que se va a mostrar cuando éste se pase por encima del con- trol de grilla, pudiendo elegir entre Arrow (flecha), Eraser (borrador), Hand (ma- no), IBean (símbolo de escritura), None (sin icono), SizeNS (cambio de tamaño norte/sur), SizeWE (cambio de tamaño oeste/este), Stylus (punto de lápiz) y Wait (reloj de arena de espera). Por último, ToolTipService.ToolTip permite mostrarle al usuario mensajes emergentes temporales cuando el mouse se posiciona duran- te determinado tiempo sobre el control de grilla. En el siguiente código, se apli- can todos los elementos mencionados: Grid x:Name=”[NombreDelControl]” ShowGridLines=”True” Cursor=”Eraser” ToolTipService.ToolTip=”Mi grilla” Width=”200” Height=”200” Grid.RowDefinitions RowDefinition Height=”70*”/ RowDefinition Height=”70”/ ... ... El código anterior deberá mostrar las líneas que delimitan la grilla, un mensaje desplegable y un cursor con forma de borrador. Todo esto, lo podemos observar en la imagen que aparece a continuación. Figura 3. Control Grid configurado con propiedades para el cursor, líneas divisorias y mensaje emergente. 4. XAML AL EXTREMO 88 04_Silverlight.qxp 9/30/09 1:31 PM Page 88
  • 91.
    Es posible tambiénespecificar la posición del control en relación con el contenedor principal. La grilla se puede colocar en cualquiera de las esquinas del contenedor, así como en el centro, e incluso especificar que ocupe toda una franja, ya sea supe- rior, inferior, izquierda o derecha de la aplicación Silverlight. Grid x:Name=”[NombreDelControl]” ShowGridLines=”True” Cursor=”Eraser” ToolTipService.ToolTip=”Mi grilla” HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch” Grid.RowDefinitions RowDefinition Height=”70*”/ Los atributos HorizontalAlignment y VerticalAlignment hacen que se pueda especifi- car la distribución de la grilla dentro del contenedor principal. Podremos usar las propiedades Left (izquierda), Center (centro), Right (derecha) y Stretch (estirado) pa- ra el atributo HorizontalAlignment. Las propiedades Top (arriba), Center (centro), Bottom (abajo) y Stretch (estirado) son válidas para el atributo VerticalAlignment. Si los dos atributos fueran configurados con la propiedad Stretch, la grilla ocuparía todo el espacio provisto por el contenedor principal, como vemos en la siguiente figura. Figura 4. Nuestra grilla ocupa el espacio disponible de su contenedor. Control GridSplitter GridSplitter no es un contenedor por sí solo, sino que se conjuga con el control Grid para poder manipular las columnas de este control y desplazarlas libremen- te. Para poder utilizarlo, en primer lugar, deberemos configurar una grilla que Controles y componentes 89 04_Silverlight.qxp 9/30/09 1:31 PM Page 89
  • 92.
    contenga dos omás columnas, o dos o más filas. GridSplitter utilizará una de estas filas o columnas para redimensionar las restantes en tiempo de ejecución. Declaramos un control GridSplitter de la siguiente manera: basics:GridSplitter x:Name=”[NombreDelControl]” Grid.Row=”[Indice de fila]” Grid.Column=”[Indice de columna]” /basics:GridSplitter Es necesario especificar la fila y la columna en la cual este control se posiciona- rá. Es importante mencionar que esta fila y columna no deberían ser usadas por otro control una vez asociado el GridSplitter. El siguiente código muestra la im- plementación completa de una grilla con un GridSplitter: Grid x:Name=”LayoutRoot” Width=”400” Height=”300” Grid.RowDefinitions RowDefinition / /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition MinWidth=”10” MaxWidth=”200” / ColumnDefinition Width=”10”/ ColumnDefinition/ /Grid.ColumnDefinitions basics:GridSplitter x:Name=”miGridSplitter” Grid.Row=”0” Grid.Column=”1” VerticalAlignment=”Stretch” HorizontalAlignment=”Center” Background=”#FFDD7676” Width=”5”/basics:GridSplitter /Grid Notemos que la primera columna de la grilla, definida por el tag ColumnDefinition, posee dos atributos: MinWidth y MaxWidth. Los valores de cada uno representan 4. XAML AL EXTREMO 90 RRR Podemos intentar la configuración del atributo HorizontalAlignment con el valor Stretch y el atri- buto VerticalAlignment con el valor Top. Con esta acción, haremos que la grilla ocupe toda la parte superior del contenedor, dejando espacio en la parte inferior. CUBRIR PARTE DEL CONTENEDOR 04_Silverlight.qxp 9/30/09 1:31 PM Page 90
  • 93.
    los valores mínimosy máximos, en este orden, a los que podrá encogerse o esti- rarse dicha columna por acción del control GridSplitter. En la figura siguiente, podemos ver estos elementos funcionando. Figura 5. GridSplitter aplicado a una grilla con atributos MinWidth y MaxWidth aplicados en la columna. En el ejemplo anterior, el control GridSplitter se visualiza y acciona de manera vertical. Podemos, por otro lado, aplicarlo de forma horizontal. Para lograr esto, tendremos que aplicar este control a las filas del control Grid y no a sus columnas: Grid x:Name=”LayoutRoot” Width=”400” Height=”300” Grid.RowDefinitions RowDefinition / RowDefinition Height=”10”/ RowDefinition MaxHeight=”200” MinHeight=”10”/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition MinWidth=”10” MaxWidth=”200” / ColumnDefinition Width=”10”/ ColumnDefinition / /Grid.ColumnDefinitions basics:GridSplitter x:Name=”miGridSplitter” Grid.Row=”0” Grid.Column=”1” VerticalAlignment=”Stretch” HorizontalAlignment=”Center” Background=”#FFDD7676” Width=”5”/basics:GridSplitter Controles y componentes 91 04_Silverlight.qxp 9/30/09 1:31 PM Page 91
  • 94.
    basics:GridSplitter x:Name=”miGridSplitterHorizontal” Grid.ColumnSpan=”3” Grid.Row=”1”Grid.Column=”0” HorizontalAlignment=”Stretch” VerticalAlignment=”Center” Background=”#FFDD7676” Height=”5”/basics:GridSplitter /Grid El código anterior realiza algunas variaciones para poder soportar un control GridSplitter de manera horizontal. En primer lugar, agregamos dos filas más a la grilla. La fila que soportará el cambio de dimensiones tiene ahora dos atributos, MinHeight y MaxHeight, que representan el valor mínimo y máximo soportado por la fila cuando se modifique su altura. Otro cambio es la cantidad de columnas que ocupará el control GridSplitter, representado por el atributo Grid.ColumnSpan colocando una unidad por cada columna que se ocupará. El resultado se puede ver en la siguiente imagen. Figura 6. En este caso, vemos dos controles GridSplitter trabajando sobre la misma grilla. Control Canvas El control Canvas es el más simple de los contenedores. Su trabajo, como conte- nedor, es el de incluir otros controles sin una estructura específica. El siguiente código muestra la declaración del control Canvas: Canvas x:Name=”[NombreDelControl]” /Canvas 4. XAML AL EXTREMO 92 04_Silverlight.qxp 9/30/09 1:31 PM Page 92
  • 95.
    El objetivo delcontrol Canvas es el de poder agrupar, de forma simple, otros ele- mentos Silverlight. De esta forma, alterando el comportamiento del control Canvas, podremos alterar el de todos los controles contenidos en él. Podemos aplicar una transformación al control Canvas para distorsionarlo, como vemos a continuación. Figura 7. Aplicando una transformación al control Canvas. A continuación, podemos ver el código de la figura anterior: Canvas x:Name=”[NombreDelControl]” HorizontalAlignment=”Stretch” RenderTransformOrigin=”0.5,0.5” Canvas.RenderTransform TransformGroup ScaleTransform/ SkewTransform AngleX=”-9” AngleY=”-5”/ RotateTransform/ TranslateTransform/ /TransformGroup /Canvas.RenderTransform El tag Canvas.RenderTransform especifica el inicio de las diferentes transfor- maciones que pueda sufrir un control. En este caso, mediante el uso del tag SkewTransform, se especifican los valores numéricos de la distorsión. Hablare- mos más sobre transformaciones en el capítulo 5. Podremos posicionar diferentes controles dentro del elemento Canvas por medio del atributo Canvas.Left (izquierda) y Canvas.Top (arriba). Estos dos atributos deben Controles y componentes 93 04_Silverlight.qxp 9/30/09 1:31 PM Page 93
  • 96.
    ser especificados enel control contenido y configuran la posición en pixeles con- tando desde la esquina superior izquierda del control Canvas. En el siguiente ejemplo, el control del botón se posicionará a 106 pixeles desde la izquierda ex- trema y 90 pixeles desde la parte superior. Button Height=”37” Width=”73” Canvas.Left=”106” Canvas.Top=”90” Content=”Click Aquí”/ Es posible combinar diferentes controles contenedores. Así podríamos usar un control Grid como contenedor principal y, en sus celdas, agrupar otros controles mediante el uso del control Canvas. Como dijimos, al agrupar otros controles dentro de un mismo contenedor, todos los cambios realizados en éste afectarán los controles incluidos, por lo que podríamos agruparlos para que queden ocultos y mostrarlos en conjunto y no individualmente. El siguiente código XAML crea un control Grid con dos columnas y dos filas; coloca dos botones en las filas superiores y un control Canvas en la fila inferior, que contiene un texto. Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions Button Margin=”46,41,69,69” Content=”Ocultar” x:Name=”BtnOcultar” Click=”BtnOcultar_Click”/ Button Margin=”46,41,69,69” Grid.Column=”1” Content=”Mostrar” x:Name=”BtnMostrar” Click=”BtnMostrar_Click”/ Canvas Grid.Row=”1” x:Name=”CanvasContenedor” TextBlock Margin=”46,66,46,50” Grid.Row=”1” Text=”Mensaje a mostrar” TextWrapping=”Wrap”/ /Canvas /Grid Como vemos en el código anterior, los botones apuntan a dos eventos manejados por C#. Este código oculta y muestra el control Canvas, ocultando y mostrando, a su vez, todos los controles contenidos por él. 4. XAML AL EXTREMO 94 04_Silverlight.qxp 9/30/09 1:31 PM Page 94
  • 97.
    private void BtnOcultar_Click(objectsender, RoutedEventArgs e) { this.CanvasContenedor.Visibility = Visibility.Collapsed; } private void BtnMostrar_Click(object sender, RoutedEventArgs e) { this.CanvasContenedor.Visibility = Visibility.Visible; } Podemos ver en la siguiente imagen cómo, al presionar el botón para ocultar el control Canvas, todo su contenido también se hace invisible. Figura 8. Una vez presionado el botón Ocultar, el control Canvas se hace invisible junto con todos sus controles contenidos. Control StackPanel Es posible que necesitemos crear una pila de controles, esto es, una sucesión de con- troles Silverlight que ocupen todo el espacio designado para éste, tanto en ancho como en alto. Pensemos en controles apilados, uno arriba del otro o uno al lado del otro. Es posible conseguir esto mediante el control StackPanel. Por lo común, usaremos el control StackPanel dentro de otros controles contenedores como vimos en el caso del control Canvas. Para declarar un control StackPanel, usaremos el siguiente código: StackPanel x:Name=”[NombreDelControl]” /StackPanel Controles y componentes 95 04_Silverlight.qxp 9/30/09 1:31 PM Page 95
  • 98.
    Al agregar nuevoscontroles dentro de StackPanel, no necesitaremos configurar atributos de posiciones debido a que éstos seguirán el flujo establecido por el StackPanel. Este flujo puede ser horizontal o vertical; para el primer caso, usaremos el atributo Orientation con el valor Horizontal, como vemos a continuación. Figura 9. En este caso, tenemos un StackPanel como contenedor principal y con flujo horizontal. En la siguiente figura, vemos cómo el flujo de los controles se muestra de manera vertical; es posible lograr esto cambiando el valor del atributo Orientation a Vertical. Figura 10. Aquí, el StackPanel como contenedor principal, está establecido con flujo vertical. 4. XAML AL EXTREMO 96 04_Silverlight.qxp 9/30/09 1:31 PM Page 96
  • 99.
    Es importante resaltarque este atributo debe ser declarado dentro del tag StackPanel, como vemos en el código que aparece a continuación: StackPanel x:Name=”[NombreDelControl]” Orientation=”[Vertical | Horizontal]” Los contenedores, como su nombre lo indica y ya hemos visto, contienen otros controles. Dentro de esta característica, se incluye la creación dinámica de otros con- troles y la posterior adición del control creado al contenedor. El siguiente código crea un nuevo control y lo adiciona al control contenedor StackPanel: Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ /Grid.ColumnDefinitions StackPanel x:Name=”StackContenedor” Button Content=”Nuevo Control” Click=”Button_Click”/ /StackPanel /Grid En el código anterior, hemos agregado un control Grid con una fila y una columna. Dentro de la celda creada, un StackPanel y, dentro de éste, un botón. Este botón disparará un evento en C# con el siguiente código: private void Button_Click(object sender, RoutedEventArgs e) { TextBox textBox = new TextBox(); textBox.Text = “Inserte texto aquí”; this.StackContenedor.Children.Add(textBox); } Cuando el usuario presiona el botón inicial, éste creará una nueva instancia de un control TextBox, le configurará un texto por mostrar y lo adicionará a la lis- ta de controles contenidos por el StackPanel. Podemos ver el resultado de pulsar varias veces el botón en la figura de la siguiente página. Controles y componentes 97 04_Silverlight.qxp 9/30/09 1:31 PM Page 97
  • 100.
    Figura 11. Diferentescontroles creados de manera dinámica a partir de una acción del usuario. Control ScrollViewer El control ScrollViewer es un contenedor que tiene la capacidad de mostrar barras de desplazamientos, tanto verticales como horizontales, dependiendo de su conte- nido. Declaramos un control ScrollViewer de la siguiente forma: ScrollViewer x:Name=”[NombreDelControl]” /ScrollViewer Podemos manipular la aparición de las barras de desplazamiento dejando que éstas se generen en forma automática sobre la base del contenido, ocultarlas por com- pleto o mostrarlas siempre. Para esto, deberemos interactuar con los atributos HorizontalScrollBarVisibility y VerticalScrollBarVisibility, pudiendo elegir como posibles valores entre Disabled, Auto, Hidden y Visible. A continuación, vemos los valores soportados por los atributos HorizontalScrollBarVisibility y VerticalScrollBarVisibility: • Disabled: esta propiedad hará que, sin importar el contenido que tenga el control ScrollViewer, las barras de desplazamiento no se muestren. • Auto: en este caso, la presencia de las barras depende del contenido. Si éste sobre- pasa las dimensiones propuestas por el ScrollViewer, las barras de desplazamientos se mostrarán de manera automática. De esta forma pueden estar visibles o no. • Hidden: en este caso, la barra de desplazamiento no se mostrará, pero el conteni- do creado dentro del control ScrollViewer que exceda el tamaño del contenedor tampoco será visible. Esta propiedad es útil cuando queramos sincronizar dos 4. XAML AL EXTREMO 98 04_Silverlight.qxp 9/30/09 1:31 PM Page 98
  • 101.
    ScrollViewer, ocultando lasbarras de desplazamiento de uno y dejando que la interacción del usuario con el segundo ScrollViewer impacte en el primero con barras de desplazamiento escondidas. • Visible: esta propiedad indica que las barras de desplazamiento se mostrarán, in- cluso, si el contenido del control ScrollViewer no excede su tamaño. Podemos ver, en el siguiente código, cómo configurar las barras de desplazamiento: ScrollViewer x:Name=”[NombreDelControl]” HorizontalScrollBarVisibility=”[Disabled | Auto | Hidden | Visible]” VerticalScrollBarVisibility=”[Disabled | Auto | Hidden | Visible]” /ScrollViewer La siguiente figura, muestra cómo se han implementado dos controles ScrollViewer, los cuales han sido sincronizados para que, sobre la base del contenido del segun- do, el primero se desplace y presente el mismo estado. Cada control ScrollViewer se encuentra en una celda de una grilla y, a su vez, cada ScrollViewer posee un con- trol StackPanel para contener otros controles. Figura 12. Dos ScrollViewer sincronizados. A continuación, podemos ver el código XAML que da vida a la figura anterior: Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions Controles y componentes 99 04_Silverlight.qxp 9/30/09 1:31 PM Page 99
  • 102.
    RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition Width=”100”/ ColumnDefinition Width=”150”/ ColumnDefinition/ /Grid.ColumnDefinitions ButtonContent=”Crear elementos” VerticalAlignment=”Top” Click=”Button_Click”/ ScrollViewer x:Name=”Scroll1” Grid.Column=”1” HorizontalScrollBarVisibility=”Visible” VerticalScrollBarVisibility=”Hidden” StackPanel x:Name=”MiStackPanel” /StackPanel /ScrollViewer ScrollViewer x:Name=”Scroll2” Grid.Column=”2” HorizontalScrollBarVisibility=”Visible” VerticalScrollBarVisibility=”Visible” LayoutUpdated=”Scroll2_LayoutUpdated” StackPanel x:Name=”SegundoStackPanel” /StackPanel /ScrollViewer /Grid Notemos que tanto al botón como a uno de los controles ScrollViewer se les han agregado eventos. En el caso del botón, el código creará controles de manera di- námica para ser agregados a los controles StackPanel que están contenidos por los ScrollViewer. En el caso del control ScrollViewer, el evento actualizará la po- sición de las barras de desplazamiento del primer ScrollViewer cada vez que éste se actualice. Podemos ver el código C# a continuación: private void Button_Click(object sender, RoutedEventArgs e) { TextBox textBox = new TextBox(); textBox.Text = “Nuevo control”; this.MiStackPanel.Children.Add(textBox); TextBox textBox2 = new TextBox(); textBox2.Text = “Nuevo TextBlock representando el TextBox”; 4. XAML AL EXTREMO 100 04_Silverlight.qxp 9/30/09 1:31 PM Page 100
  • 103.
    this.SegundoStackPanel.Children.Add(textBox2); } private void Scroll2_LayoutUpdated(objectsender, EventArgs e) { this.Scroll1.ScrollToVerticalOffset(this.Scroll2.VerticalOffset); } Como vemos en la Figura 13, al agregar controles de manera dinámica, el control ScrollViewer de la derecha muestra una barra de desplazamiento vertical, pero el otro ScrollViewer no presenta barra de desplazamiento alguna a pesar de tener tantos elementos como el de la derecha. Al mover la barra de desplazamiento del ScrollViewer de la derecha, también se desplaza el otro. Figura 13. A pesar de que uno contiene barras de desplazamiento visibles y el otro no, ambos ScrollViewer están sincronizados. Control Border El control Border es el más simple de los controles, aunque puede resultar extre- madamente útil. Como su nombre en inglés lo indica, el control Border (borde o contorno) marca un borde a lo que contiene. Ya lo hemos usado en el capítulo 2 al crear un contorno para la película en nuestro visor de videos. De cualquier mane- ra, este control posee otros atributos que resultan útiles. Es posible asignarle un grosor a cada lado del borde, así como crear esquinas redondeadas. A continua- ción podemos ver la declaración de un control Border: Controles y componentes 101 04_Silverlight.qxp 9/30/09 1:31 PM Page 101
  • 104.
    Border x:Name=”[NombreDelControl]” /Border Para asignarlos valores al borde, usamos el atributo BorderThickness, empleando un valor numérico en pixeles correspondiente al borde izquierdo, superior, derecho e in- ferior, en ese orden, separado por comas. El atributo CornerRadius especifica el radio numérico de curvatura de las esquinas pudiendo determinar los valores para la esqui- na superior izquierda, superior derecha, inferior derecha e inferior izquierda, separados por comas. Veamos, a continuación, un control Border configurado: Border BorderThickness=”5,5,5,5” BorderBrush=”#FFA76666” CornerRadius=”10,10,0,0” /Border Figura 14. Control Border configurado con grosor de 5 pixeles y redondeado en las esquinas superiores. 4. XAML AL EXTREMO 102 , Los símbolos de corchetes usados en el código de ejemplo representan elementos que deben ser reemplazados en el momento de la escritura del código real. Debemos cambiar estos valo- res por aquellos que sean convenientes para la aplicación que estemos realizando. SÍMBOLO DE CORCHETE 04_Silverlight.qxp 9/30/09 1:31 PM Page 102
  • 105.
    Controles de interaccióncon el usuario Los controles que veremos listados a continuación son aquellos que presentan la posibilidad de interactuar con el usuario, en especial, para capturar datos y ac- ciones que éste realice o para presentarle información. Como podemos imaginar, son los controles más utilizados en cualquier interfaz. Control Button El control Button o botón es uno de los más conocidos y, prácticamente, lo en- contramos en todas las interfaces visuales. Posee como objetivo principal el de disparar acciones por parte del usuario. Su declaración es intuitiva, como po- demos ver en el código que aparece a continuación: Button x:Name=”[NombreDelControl]” Content=”[Texto del Botón]” /Button El atributo Content hace referencia al texto que se mostrará en el interior del con- trol. La función primordial del control Button es la de poder capturar el clic del mouse y así disparar un evento para que nuestra pieza de código reaccione a éste. Podremos enlazar este evento a nuestro código agregando el atributo Click a la descripción del control más el nombre de la función en nuestro código C# que se utilizará para ejecutar el evento en cuestión. Button x:Name=”[NombreDelControl]” Content=”[Texto del Botón]” Click=”[NombreDeFuncion]” /Button La función por utilizar debe seguir una firma o contener una serie de parámetros exactos; sin esta firma, el evento no podrá ser enlazado en forma correcta. private void [NombreDeFuncion](object sender, RoutedEventArgs e) El elemento sender de tipo object contiene el objeto ejecutor del evento. Este parámetro es importante, ya que podríamos tener asociados a la misma función diferentes eventos Click de distintos botones. En el siguiente código, se crean tres controles del tipo Button desde nuestro código, asociando cada uno de ellos a la misma función creada con anterioridad. Cada vez que se dispare el evento de cualquiera de los botones, se tomará ese texto, haciendo uso del objeto sender, para informar qué botón realizó la acción. Primero declaramos el código XAML: Controles y componentes 103 04_Silverlight.qxp 9/30/09 1:31 PM Page 103
  • 106.
    Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinitionWidth=”0.332*”/ ColumnDefinition Width=”0.51*”/ ColumnDefinition Width=”0.158*”/ /Grid.ColumnDefinitions StackPanel x:Name=”MiStackPanel” Button Click=”Button_Click” Content=”Botón XAML” HorizontalContentAlignment=”Center”/ /StackPanel TextBlock x:Name=”mensaje” HorizontalAlignment=”Stretch” Margin=”8,8,0,0” VerticalAlignment=”Stretch” Grid.Column=”1” Text=”” TextWrapping=”Wrap”/ /Grid Luego, el código que generará los botones y enlazará los eventos: public partial class Page : UserControl { public Page() { InitializeComponent() CrearBotones(); } private void CrearBotones() { for (int i = 0; i 3; i++) { Button boton = new Button(); boton.Click += new RoutedEventHandler(Button_Click); boton.Content = “Botón “ + i.ToString(); this.MiStackPanel.Children.Add(boton); } } 4. XAML AL EXTREMO 104 04_Silverlight.qxp 9/30/09 1:31 PM Page 104
  • 107.
    private void Button_Click(objectsender, RoutedEventArgs e) { this.mensaje.Text = “Presionado: “ + ((Button)sender).Content; } } Cada uno de los botones creado en la función CrearBotones() es adicionado a un control StackPanel, además de asociar el evento Click a la función Button_Click(). En la siguiente figura, podemos ver cómo se han creado los botones y también el resultado que se muestra cuando se presiona cada botón. Figura 15. Lista de controles creados en forma dinámica con eventos asociados. El control Button también posee la capacidad de incluir, dentro de él, otros con- troles. Éste es el caso en el cual podemos redefinir su formato por medio de un control Image. Si lo colocamos dentro del tag del control Button, podremos ha- cer que la cara visible sea igual a la imagen seleccionada. Controles y componentes 105 RRR Cuando trabajamos con contenedores, debemos tener en cuenta que es posible colocar sólo un con- tenedor por página Silverlight. Si bien se pueden anidar controles del tipo contenedor, solamente debe existir uno a nivel general, es decir, ubicado entre los tags UserControl/UserControl. CONTENEDORES 04_Silverlight.qxp 9/30/09 1:31 PM Page 105
  • 108.
    Button x:Name=”[NombreDelControl]” Image Height=”[Altoen píxeles]” Width=”[Ancho en píxeles]” Source=”[Nombre de la imágen]”/ /Button En la siguiente figura, es posible ver el nuevo botón usando una imagen como cara visible. Cabe destacar que el comportamiento de eventos en el botón será exactamente igual que un botón sin otro elemento anidado. Figura 16. Un botón anidando una imagen. Control CheckBox Este control, conocido también como de casilla de verificación, presenta, típica- mente, un cuadrado donde el usuario puede marcar o desmarcar la casilla. Para de- clarar un control CheckBox, podremos hacerlo de la siguiente forma: CheckBox x:Name=”[NombreDelControl]” Content=”[Texto del CheckBox]” /CheckBox En este caso, el atributo Content mostrará el texto escrito al margen derecho de la casilla de verificación. Este control posee los dos estados comunes para este tipo de controles, que pueden variar entre verificado y no verificado. Pero también es posible obtener con él un tercer estado para casos donde se requiera un estado parcialmente verificado o indeterminado. Para lograr esto, tendremos que hacer uso del atributo IsThreeState, colocando como valor True (verdadero). 4. XAML AL EXTREMO 106 04_Silverlight.qxp 9/30/09 1:31 PM Page 106
  • 109.
    CheckBox Content=”C#” IsThreeState=”True” HorizontalContentAlignment=”Left”/ También esposible especificar que el control esté en estado verificado por defecto, haciendo uso del atributo IsChecked con su valor igual a True. CheckBox Content=”C#” IsChecked=”True” HorizontalContentAlignment=”Left”/ En la figura que aparece a continuación, se muestra cómo los controles CheckBox presentan el comportamiento configurado en cada caso. Figura 17. Un control CheckBox por cada opción disponible. Este control puede poseer cuatro eventos para disparar por cada uno de los estados. • Click: este evento es disparado cuando el usuario presiona el control CheckBox con el botón del mouse. • Checked: sólo se disparará cuando el control pase al estado de verificado. • Unchecked: en este caso, el evento será ejecutado sólo cuando el control pase de cualquier estado a no verificado. • Indeterminate: si hemos configurado el atributo IsThreeState a verdadero, este evento se disparará cuando el control entre en el tercer estado de selección. Controles y componentes 107 04_Silverlight.qxp 9/30/09 1:31 PM Page 107
  • 110.
    El siguiente códigoXAML muestra todas las configuraciones posibles. En este caso, se han configurado eventos para el segundo control CheckBox: Grid x:Name=”LayoutRoot” Background=”White” StackPanel HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch” TextBlock Text=”¿En qué lenguaje programas?” TextWrapping=”Wrap”/ CheckBox Content=”C#” IsChecked=”True” HorizontalContentAlignment=”Left”/ CheckBox Content=”Visual Basic.Net” IsThreeState=”True” HorizontalContentAlignment=”Left” Click=”CheckBox_Click” Checked=”CheckBox_Checked” Indeterminate=”CheckBox_Indeterminate” Unchecked=”CheckBox_Unchecked”/ CheckBox Content=”Java” IsThreeState=”True” HorizontalContentAlignment=”Left”/ TextBlock Text=”” TextWrapping=”Wrap” x:Name=”mensaje”/ /StackPanel /Grid Para capturar los eventos, deberemos escribir el siguiente código C#: private void CheckBox_Click(object sender, RoutedEventArgs e) { } private void CheckBox_Checked(object sender, RoutedEventArgs e) { this.mensaje.Text = “Usted usa Visual Basic.net”; } private void CheckBox_Indeterminate(object sender, RoutedEventArgs e) { this.mensaje.Text = “No está seguro si usa o no Visual Basic.net”; } 4. XAML AL EXTREMO 108 04_Silverlight.qxp 9/30/09 1:31 PM Page 108
  • 111.
    private void CheckBox_Unchecked(objectsender, RoutedEventArgs e) { this.mensaje.Text = “Usted no usa Visual Basic.net”; } En el código anterior, no hemos colocado líneas adicionales en el evento Click debido a que éste se disparará en todas las oportunidades que el usuario presione el control, sin importar el estado al cual pasará en cada clic. El resultado debería ser el siguiente: Figura 18. Al pasar al estado indeterminado, es desplegado el mensaje correspondiente. Si bien podemos usar los eventos para recuperar información de los controles, existirán casos donde estos eventos no sean necesarios, pero sí conocer el estado de los controles por medio de nuestro código. Para poder acceder al control, es necesario asignarle un nombre descriptivo. CheckBox Content=”Visual Basic.Net” IsThreeState=”True” HorizontalContentAlignment=”Left” Click=”CheckBox_Click” Checked=”CheckBox_Checked” Indeterminate=”CheckBox_Indeterminate” Unchecked=”CheckBox_Unchecked” x:Name=”VBCheckBox”/ Una vez nombrado el control, podremos usar la propiedad IsChecked para accede al valor actual del elemento. Esta propiedad es un valor del tipo Verdadero/Falso que, además, cuenta con el atributo Nulleable, lo que significa que puede mantener tres Controles y componentes 109 04_Silverlight.qxp 9/30/09 1:31 PM Page 109
  • 112.
    estados, True (verdadero),False (falso) y Null (nulo). Estos tres valores representan los tres posibles estados del control, siendo verdadero para el estado verificado, falso para no verificado y nulo para indeterminado. Como se observa a continua- ción, el estado del control CheckBox se escribe en la consola de depuración. System.Diagnostics.Debug.WriteLine(“CheckBox verificado: “ + this.VBCheckBox.IsChecked.ToString()); Control RadioButton El control RadioButton extiende la funcionalidad del control CheckBox antes visto. Si bien éste se presenta como una casilla de verificación, el formato visual tradicional es de un círculo, donde puede ser seleccionado uno de éstos en un grupo de con- troles similares. El control RadioButton tiene el objetivo de presentar opciones de manera grupal, donde el usuario pueda seleccionar una de ese grupo, a diferencia del CheckBox, donde el usuario puede seleccionar tantas opciones como crea con- veniente. Podemos declarar un control RadioButton de la siguiente forma: RadioButton x:Name=”[NombreDelControl]” Content=”[Texto del RadioButton]” /RadioButton Como hemos dicho, el objetivo de este control es el trabajo en conjunto con otros similares de manera grupal. Para lograr este efecto, es necesario especificar, para cada control RadioButton, el nombre del grupo al cual pertenece. Todos los controles RadioButton con el mismo grupo actuarán como una unidad, pasando del estado verificado a no verificado en forma automática. Para configurar un grupo, debere- mos usar el atributo GroupName, colocando el nombre del grupo correspondiente. Grid x:Name=”LayoutRoot” Background=”White” StackPanel TextBlock Text=”Género:”/TextBlock RadioButton Content=”Masculino” GroupName=”Sexo”/ RadioButton Content=”Femenido” GroupName=”Sexo”/ /StackPanel /Grid El código anterior muestra cómo podemos agrupar dos controles RadioButton me- diante el atributo GroupName. Si colocamos los dos controles dentro del mismo grupo, obtendremos el resultado de la figura en la página siguiente. 4. XAML AL EXTREMO 110 04_Silverlight.qxp 9/30/09 1:31 PM Page 110
  • 113.
    Figura 19. ControlesRadioButton en un mismo grupo. Es posible generar tantos grupos cono necesitemos. Cada conjunto de controles RadioButton trabajará de manera independiente. El siguiente código extiende el anterior, agregando dos columnas a la grilla y generando un nuevo grupo de con- troles RadioButton en la segunda columna: Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions StackPanel TextBlock Text=”Género:”/TextBlock RadioButton Content=”Masculino” GroupName=”Sexo”/ RadioButton Content=”Femenido” GroupName=”Sexo”/ /StackPanel StackPanel Grid.Column=”1” TextBlock Text=”Edad:”/ RadioButton Content=”Menor de 18 años” GroupName=”Edad”/ RadioButton Content=”Mayor de 18 años” GroupName=”Edad”/ /StackPanel /Grid Controles y componentes 111 04_Silverlight.qxp 9/30/09 1:31 PM Page 111
  • 114.
    De esta forma,tenemos dos grupos, uno definido por el valor Sexo y otro por Edad. Al seleccionar cualquiera de los elementos de un grupo, éstos trabajarán de ma- nera independiente o en relación con su grupo. Figura 20. Dos grupos de RadioButton trabajando de manera independiente. El control RadioButton, al igual que el control CheckBox, puede mostrarse verifi- cado desde el inicio mediante el atributo IsChecked, configurando su valor a True (verdadero), como vemos a continuación: RadioButton Content=”Mayor de 18 años” GroupName=”Edad” IsChecked=”true”/ Este control posee eventos similares al del control CheckBox. Es posible enlazar eventos a la acción de presionado del mouse y al cambio de su estado. Como las posibilidades del control RadioButton son más limitadas que las del control CheckBox, 4. XAML AL EXTREMO 112 Dentro de la librería de recursos provista por Microsoft en la Web, podremos encontrar una sección que hace referencia a la aplicación de reglas, recomendaciones y otros elementos re- lacionados con el momento del desarrollo de aplicaciones para Windows. Para poder ingresar en este sitio, deberemos navegar a la siguiente dirección: http://msdn.microsoft.com/. APRENDIENDO SOBRE UX 04_Silverlight.qxp 9/30/09 1:31 PM Page 112
  • 115.
    consideremos que novamos a tener disponible el evento Indeterminate, así co- mo la propiedad que da vida a esta capacidad. Podemos ver un ejemplo de los eventos disponibles para este control a continuación: RadioButton Content=”Mayor de 18 años” GroupName=”Edad” IsChecked=”true” Click=”RadioButton_Click” Checked=”RadioButton_Checked” x:Name=”RadioButtonMayor18”/ El enlace de estos eventos en nuestro código C#. private void RadioButton_Click(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine(“Mayor de 18 años presionado”); } private void RadioButton_Checked(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine(“Estado del control: “ + this.RadioButtonMayor18.IsChecked.ToString()); } Control HyperlinkButton El control HyperlinkButton es uno de los controles más simples de manipular. Su objetivo consiste en proveer de un enlace o vínculo para navegar desde nuestra apli- cación hacia otra dirección web. Teniendo en cuenta que las aplicaciones Silverlight son hospedadas por los navegadores web en un ambiente web, este control resulta fundamental en cualquier proyecto que llevemos a cabo. Cuenta con dos atributos primarios: Content, como en controles anteriores, es usado para desplegar el texto que mostrará el control; y NavigateUri contiene el valor de la URL o página adon- de el navegador web se dirigirá. A continuación, veamos un ejemplo: Controles y componentes 113 RRR Un cambio significativo en los lenguajes de programación basados en Microsoft.Net fue la in- corporación de un nuevo estado para los tipos de datos. Este tipo se denomina Nulleable, o tipo de dato con soporte de nulos, y hace que el dato nulo también sea considerado un valor. ESTADOS DE LAS VARIABLES 04_Silverlight.qxp 9/30/09 1:31 PM Page 113
  • 116.
    HyperlinkButton Content=”Ir aRedUsers” NavigateUri=”http://www.redusers.com” /HyperlinkButton Control Image El control Image presenta un comportamiento particular. Si bien es utilizado pa- ra desplegar imágenes en nuestras aplicaciones Silverlight, este control nos per- mite visualizar imágenes que estén contenidas tanto en nuestra aplicación como en cualquier otra dirección web válida. La diferencia de estas dos posibilidades radica en el tamaño del archivo generado por nuestra aplicación y qué cantidad de información estaremos dispuestos a transferir al cliente que la consuma. Pensemos que las imágenes adicionadas a nuestros proyectos Silverlight son empaquetadas dentro del archivo de aplicación de Silverlight, y éste debe ser descargado por completo antes de poder ejecutarse. Como vemos en la figura que aparece deba- jo, el archivo logo.jpg es incluido en el proyecto para luego ser visualizado por el control Image desde el mismo archivo. Figura 21. Podemos ver la imagen incluida en el proyecto, a la derecha, en el explorador de soluciones. Al compilar el proyecto, Visual Studio 2008 generará un archivo que tendrá la extensión XAP (eXtended Application Package). Este archivo es el resultado de nuestro proyecto, tanto del código como de todas las imágenes incluidas dentro de él, por lo que, mientras más imágenes agreguemos, este archivo crecerá en ta- maño y, por ende, se deberá descargar un archivo mayor en el cliente, que hará más lenta la ejecución inicial de la aplicación. 4. XAML AL EXTREMO 114 04_Silverlight.qxp 9/30/09 1:31 PM Page 114
  • 117.
    Figura 22. ArchivoXAP creado en la compilación de la aplicación Silverlight. Por lo dicho antes, es necesario encontrar un balance entre los archivos de imá- genes que vamos a incluir dentro del proyecto y aquellos que deberemos consumir de manera dinámica desde otro recurso de red. Para declarar un control Image, podemos hacerlo con el siguiente código: Image Source=”[Nombre de la imagen | Ruta de acceso de la imagen]”/Image Si agregamos la imagen a nuestra solución, con sólo colocar su nombre, podre- mos visualizarla dentro del control Image. Por el contrario, colocando la direc- ción web completa de la imagen por visualizar, el control Image la consumirá desde su origen. Veamos ejemplos de ambas formas: Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ /Grid.ColumnDefinitions Controles y componentes 115 04_Silverlight.qxp 9/30/09 1:31 PM Page 115
  • 118.
    Image Source=”logo.jpg”/Image Image Source=”http://www.redusers.com/wp- content/themes/redusers/images/logo.jpg”Grid.Row=”1”/Image /Grid En el código anterior, hemos colocado dos controles Image, uno que utiliza una ima- gen incluida en el mismo proyecto Silverlight y la segunda que consume la misma imagen desde su origen web. En la siguiente figura, podemos ver el resultado. Figura 23. Arriba, la imagen tomada desde la solución. Abajo, consumida desde su dirección web. Este control también cuenta con un atributo llamado Stretch, que es utilizado para configurar el comportamiento de la imagen sobre la base del tamaño elegido para el control Image. Los valores del atributo Stretch pueden ser los siguientes: • None: este atributo no aplicará ningún cambio a la imagen contenida por el con- trol Image y la mostrará en su tamaño original, incluso, cortando partes de ésta si es más grande que su contenedor. • Fill: sin importar el tamaño original de la imagen, ésta se ajustará al contenedor Image para ocupar o rellenar por completo el tamaño del control. Esto puede cau- sar la deformación de la imagen. • Uniform: al igual que Fill, esta propiedad rellenará todo el contenedor con la ima- gen, pero ajustándola sin deformarla. • UniformToFill: este valor es la conjunción de los dos anteriores. Ajusta la imagen para que llene por completo el contenedor sin deformarla. 4. XAML AL EXTREMO 116 04_Silverlight.qxp 9/30/09 1:31 PM Page 116
  • 119.
    Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions ImageSource=”logo.jpg” Stretch=”None”/Image Image Source=”http://www.redusers.com/wp- content/themes/redusers/images/logo.jpg” Grid.Row=”1” Stretch=”Fill”/Image Image Source=”logo.jpg” Grid.Column=”1”/ Image Source=”logo.jpg” Grid.Column=”1” Grid.Row=”1” Stretch=”UniformToFill”/ /Grid Figura 24. Aplicando los cuatro modificadores posibles para el control Image. Control ComboBox El objetivo del control ComboBox es el de brindarle al usuario la posibilidad de elegir un elemento de entre un conjunto de elementos o lista de éstos. Como todos los con- troles comúnmente usados en el desarrollo de software, entre sus objetivos está el de optimizar las interfaces gráficas para brindar una mejor experiencia al usuario. Parte de esta optimización radica en la capacidad de reducir los elementos o controles Controles y componentes 117 04_Silverlight.qxp 9/30/09 1:31 PM Page 117
  • 120.
    presentados en pantallatratando de no sobrecargar, en lo visual, al usuario. El control ComboBox puede presentar una gran cantidad de información en un espacio reducido. La declaración del control ComboBox podemos verla a continuación: ComboBox x:Name=”[NombreDelControl]” /ComboBox Como el ComboBox representa una lista de elementos entre los que se debe elegir alguno, es necesario que agreguemos tantos elementos como necesitemos mostrar, entre los cuales el usuario seleccionará. Para hacer esto, deberemos incluir el tag ComboBoxItem dentro del tag representativo del control ComboBox. ComboBox VerticalAlignment=”Top” Margin=”0,0,165,0” Height=”38” Grid.Row=”1” ComboBoxItem Content=”Item 1”/ComboBoxItem ComboBoxItem Content=”Item 2”/ComboBoxItem ComboBoxItem Content=”Item 3”/ComboBoxItem ComboBoxItem Content=”Item 4”/ComboBoxItem ComboBoxItem Content=”Item 5”/ComboBoxItem /ComboBox El código anterior genera un control ComboBox con cinco elementos, que se mostrarán en una lista desplegable al momento de presionar sobre la flecha derecha del control. Figura 25. ComboBox desplegado para seleccionar uno de los ítems de la lista. 4. XAML AL EXTREMO 118 04_Silverlight.qxp 9/30/09 1:31 PM Page 118
  • 121.
    Una vez seleccionadoun ítem de la lista, es posible saber cuál de los elementos lista- dos es el que fue seleccionado. Esto es útil para recolectar los valores elegidos por el usuario en la aplicación. Para comprobar cuál ha sido el elemento marcado, prime- ro deberemos asignarle un nombre al control ComboBox ya que, de esta forma, lo ac- cederemos desde nuestro código. El siguiente código XAML muestra cómo hacerlo: ComboBox x:Name=”ComboBox1” VerticalAlignment=”Top” Margin=”0,0,165,0” Height=”38” Grid.Row=”1” ComboBoxItem Content=”Item 1”/ComboBoxItem ComboBoxItem Content=”Item 2”/ComboBoxItem ComboBoxItem Content=”Item 3”/ComboBoxItem ComboBoxItem Content=”Item 4”/ComboBoxItem ComboBoxItem Content=”Item 5”/ComboBoxItem /ComboBox TextBlock x:Name=”mensaje” HorizontalAlignment=”Left” VerticalAlignment=”Top” TextWrapping=”Wrap” Grid.Row=”1” Margin=”0,42,0,0”/ Button HorizontalAlignment=”Right” Click=”Button_Click” VerticalAlignment=”Top” Content=”Aceptar” Grid.Row=”1” Margin=”0,0,84.808,0” Height=”38” Width=”76”/ También hemos agregado un control Button y un control TextBlock, el mismo que hemos usado en otros ejemplos y del que hablaremos un poco más adelante. Una vez hecho esto, pasaremos al código C#, donde colocaremos la lógica que captura esta información dentro del método disparado por el evento Click del botón. private void Button_Click(object sender, RoutedEventArgs e) { this.mensaje.Text = ((ComboBoxItem)this.ComboBox1.SelectedItem).Content.ToString(); } Por medio de la propiedad SelectedItem del control ComboBox, es posible obtener un objeto del tipo Object. Este objeto es la representación del tipo de elemento seleccio- nado. En el código de este ejemplo, habíamos utilizado un elemento ComboBoxItem como tipo de objeto para cada ítem del ComboBox. Por este motivo, el objeto devuelto por la propiedad SelectedItem será, internamente, de este tipo, razón por la cual reali- zamos un Cast (Conversión) del tipo Object a un tipo ComboBoxItem, accediendo por último a la propiedad Content, que almacena el valor de este elemento. Controles y componentes 119 04_Silverlight.qxp 9/30/09 1:31 PM Page 119
  • 122.
    Figura 26. Unavez seleccionado el elemento, el valor de éste es mostrado en el control TextBlock. Si bien podemos agregar ítems por medio de la escritura de XAML como en el ejem- plo anterior, es posible adicionar nuevos elementos desde nuestro código. De la mis- ma forma que con XAML, necesitamos crear un nuevo elemento ComboBoxItem, configurando sus propiedades y adicionándolo, en definitiva, al control ComboBox. A continuación, vemos cómo hacerlo: public void CargarCombo() { for (int i = 0; i 10; i++) { this.ComboPorCodigo.Items.Add(new ComboBoxItem() { Content = “Item “ + i.ToString() }); } } 4. XAML AL EXTREMO 120 , En el código de ejemplo, el símbolo | (Pipe) presenta una condición OR (Uno u otro). Este sím- bolo representa la posibilidad de elegir para las propiedades una u otra de las listadas. Como existen propiedades con más de dos valores seleccionables, éstos se encontrarán delimitados por tantos | como valores contenga. SÍMBOLO PIPE 04_Silverlight.qxp 9/30/09 1:31 PM Page 120
  • 123.
    El código crearádiez elementos ComboBoxItem, adicionándolos al control ComboBox. Podemos ver el resultado del despliegue de la lista de elementos en la siguiente imagen: Figura 27. ComboBox desplegado con elementos creados en forma dinámica. Contamos con una tercera forma de crear elementos para un control ComboBox. Es- ta forma es la de enlazado de datos. El enlazado de datos nos facilita la tarea de crear elementos por nuestra cuenta, al mismo tiempo que estos datos podrían ser obtenidos al ejecutar una consulta a una base de datos, servicio web o cualquier otro que pudiera retornar una colección de elementos. public void CargarComboEnlazado() { Liststring datos = new Liststring(); for (int i = 0; i 10; i++) { datos.Add(“Item “ + i.ToString()); } this.ComboEnlazado.ItemsSource = datos; } En este ejemplo simple, en lugar de cargar directamente los elementos sobre el ComboBox por cada iteración del ciclo, simulamos una colección de datos por medio de una lista genérica, asignando esta lista a la propiedad ItemsSource del control ComboBox. Esta asignación disparará el llenado del control con sus ele- mentos, pudiendo manipularlos como vemos en la siguiente figura. Controles y componentes 121 04_Silverlight.qxp 9/30/09 1:31 PM Page 121
  • 124.
    Figura 28. Elcontrol ComboBox desplegado fue cargado por medio del enlazado de datos. Como en otros controles, el ComboBox posee una serie de eventos para poder cap- turar determinadas acciones del usuario y disparar código C#. Algunos de los prin- cipales eventos los encontramos en la siguiente lista: • DropDownOpened: este evento es disparado cuando el usuario despliega la lista con todos los elementos posibles de selección. Puede resultar muy útil para la carga de datos realizada de manera asíncrona, haciéndola sólo en el momento en el que la lista desplegable es mostrada. • DropDownClosed: este evento representa la acción inversa al DropDownOpened. Una vez el usuario seleccione un elemento y la lista se cierre, este evento será disparado. • SelectionChanged: cada vez que el usuario selecciona un nuevo elemento de la lis- ta, éste pasa a ser el elemento seleccionado, cambiando de estado la selección, así como los índices utilizados. Este evento es útil cuando necesitamos cargar ele- mentos sobre la base de la selección de un ítem específico. Para incluir el manejo de los eventos, podemos modificar el ComboBox como vemos en el código que aparece a continuación ComboBox x:Name=”ComboEnlazado” DropDownClosed=”ComboEnlazado_DropDownClosed” DropDownOpened=”ComboEnlazado_DropDownOpened” SelectionChanged=”ComboEnlazado_SelectionChanged” / 4. XAML AL EXTREMO 122 04_Silverlight.qxp 9/30/09 1:31 PM Page 122
  • 125.
    Cada método definidoen el código XAML también deberá estar presente en nuestro código C#. Este código mostrará los diferentes mensajes basados en la acción aplicada en el control ComboBox. Veamos: private void ComboEnlazado_DropDownClosed(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine(“Lista desplegable cerrada”); } private void ComboEnlazado_DropDownOpened(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine(“Lista desplegable abierta”); } private void ComboEnlazado_SelectionChanged(object sender, SelectionChangedEventArgs e) { System.Diagnostics.Debug.WriteLine(“Nuevo elemento seleccionado”); } En todo caso, el control ComboBox no se limita a las características que ya hemos visto. Este control es extremadamente versátil, pudiendo adicionar elementos de diferentes tipos a la lista desplegable. Esto quiere decir que no estamos limitados a mostrar ítems de sólo texto, sino que tendremos la capacidad de agregar elementos complejos como controles RadioButton, CheckBox, Image, entre otros. El siguiente código XAML demuestra cómo es posible agregar otro tipo de elementos al control ComboBox: ComboBox ListBoxItem Content=”Item 1”/ CheckBox Content=”Item 2”/ ComboBoxItem Content=”Item 3”/ RadioButton Content=”Item 4”/ Image Source=”http://www.redusers.com/wp- content/themes/redusers/images/logo.jpg”/ /ComboBox Como podemos ver en el código anterior, el control ComboBox poseerá varios ele- mentos, entre los que encontraremos un CheckBox, un RadioButton y un control Image. En la Figura 29 podemos ver este ComboBox en pleno funcionamiento. Controles y componentes 123 04_Silverlight.qxp 9/30/09 1:31 PM Page 123
  • 126.
    Figura 29. ElComboBox tiene elementos complejos dentro de sus elementos seleccionables. Al seleccionar el ítem del ComboBox, éste pasará a visualizarse como el elemento se- leccionado, presentando el mismo comportamiento que otros elementos, con la dife- rencia de que, al ser un elemento compuesto, éste también poseerá las características de complejidad del control utilizado. En la Figura 30, el ítem representado por un con- trol CheckBox también incluye la funcionalidad de utilizar la casilla de verificación. Figura 30. Un control CheckBox como elemento de un control ComboBox. Control ListBox El control ListBox es homónimo del control ComboBox que ya vimos. La diferencia de este control es su capacidad de mostrar la lista de elementos no en una lista desplega- 4. XAML AL EXTREMO 124 04_Silverlight.qxp 9/30/09 1:31 PM Page 124
  • 127.
    ble, sino demanera constante, utilizando una barra de desplazamiento para movernos a través de la lista. Para crear un control ListBox, usamos la siguiente sintaxis: ListBox x:Name=”[NombreDelControl]” /ListBox Como el control ListBox posee el mismo comportamiento que el ComboBox, es po- sible incluir los mismos elementos complejos, así como elementos simples dentro de la lista de ítems por mostrar y posibles de selección. ListBox VerticalAlignment=”Top” Height=”94” ListBoxItem Content=”Item 1”/ ListBoxItem Content=”Item 2”/ RadioButton Content=”Masculino” GroupName=”Sexo”/ RadioButton Content=”Femenino” GroupName=”Sexo”/ Image Source=”http://www.redusers.com/wp- content/themes/redusers/images/logo.jpg”/Image /ListBox El código anterior muestra cinco elementos entre los cuales podemos encontrar un grupo de controles RadioButton y un control Image. El atributo Height (alto) es usa- do como el condicionante para, además de configurar la altura del control, poder indicar cuántos elementos deberán ser mostrados en la lista inicial. Figura 31. ListBox con elementos complejos. Controles y componentes 125 04_Silverlight.qxp 9/30/09 1:31 PM Page 125
  • 128.
    Como hemos comentado,este control podría considerarse una extensión del control ComboBox, por lo que la forma de manipularlo por código, recolectar el elemento se- leccionado, cargar nuevos elementos e interactuar con los eventos resulta similar. Úni- camente encontraremos una diferencia en la cantidad de eventos disponibles. Debido a que este control no posee una lista desplegable, los dos eventos correspondientes al accionar de la lista no estarán disponibles para su uso, por lo que sólo podremos usar el evento SelectionChanged, que se disparará cada vez que se accione un nuevo elemento. Control TextBlock El control TextBlock es, sin dudas, el más simple de los controles, incluso más senci- llo que el control HyperlinkButton visto en páginas anteriores. El control TextBlock cumple la función de mostrar un texto en nuestra aplicación. Este control es útil en especial para mostrar textos informativos al usuario, así como para complementarlo con otros controles o en la creación de nuevos controles que requieran desplegar tex- tos. La declaración de este control se reduce a las siguientes líneas de código: TextBlock x:Name=”[NombreDelControl]” Text=”[Texto a visualizar]” /TextBlock Necesitaremos de un nombre para poder utilizarlo en nuestro código. Podremos ma- nipular la información desplegada por este control mediante el atributo Text (texto), configurándolo en el código XAML o mediante código de forma dinámica. El acce- so desde nuestro código resulta bastante sencillo, como se muestra a continuación: public void MostrarMensaje() { this.MiTextBlock.Text = “Mensaje de bienvenida”; } El atributo Text usado en el código XAML es el mismo que se transforma en la pro- piedad Text en nuestro código, el mismo que usaremos para asignar o recolectar valo- res desde el control. Como todo componente para desplegar textos, es necesario que posea la capacidad de darle formato a ese texto, permitiendo variar su color, tipo y ta- maño de fuente, entre otras opciones. En el siguiente ejemplo, adicionamos algunas propiedades al control TextBlock para cambiar el tamaño, color y tipo de fuente usada. TextBlock x:Name=”MiTextBlock” Text=”” FontFamily=”Comic Sans MS” FontSize=”18” FontWeight=”Bold” 4. XAML AL EXTREMO 126 04_Silverlight.qxp 9/30/09 1:31 PM Page 126
  • 129.
    TextBlock.Foreground LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStopColor=”#FFEEE659”/ GradientStop Color=”#FF1120A2” Offset=”1”/ /LinearGradientBrush /TextBlock.Foreground /TextBlock Para este caso, agregamos los atributos FontFamily, FontSize y FontWeight. Estos atri- butos son utilizados para configurar el tipo de fuente, su tamaño y sus modificado- res como, por ejemplo, Bold (negrita), Normal y otros. También hemos agregado más elementos para modificar el color de la fuente, usando un color degradado (hablaremos más de este tema en los siguientes capítulos). Figura 32. TextBlock con un tipo de fuente diferente de la configurada por defecto. Control TextBox Al igual que el control anterior, el control TextBox es uno de los más comunes en el de- sarrollo de aplicaciones, y ya lo hemos usado en varios de los ejemplos a través de los capítulos de este libro. Este control es el control básico para introducción de texto por parte del usuario, permitiéndole escribir texto libremente para que sea procesado por nuestra aplicación. Este control posee una declaración XAML muy simple: TextBox x:Name=”[NombreDelControl]” Text=”[Texto a visualizar]” /TextBox Controles y componentes 127 04_Silverlight.qxp 9/30/09 1:31 PM Page 127
  • 130.
    En el controlTextBox es posible especificar el comportamiento que tendrá el flujo del texto escrito. Por ejemplo, si tenemos un control TextBox con un tamaño en alto ma- yor a más de una línea de texto, es posible usar el atributo TextWrapping para que, cuan- do el texto llegue al final de la caja de texto, continúe en la siguiente línea. Si omitimos esta propiedad o colocamos el valor del atributo igual a NoWrap, el texto seguirá su flu- jo normal y los caracteres más antiguos escritos desaparecerán del rango visual, tenien- do que desplazarnos con el teclado para poder volver a ver esa información. TextBox Text=”” TextWrapping=”[Wrap | NoWrap]” /TextBox Figura 33. El TextBox superior utiliza la propiedad Wrap y el de abajo usa NoWrap. También podemos necesitar cajas de texto para introducción de texto extenso. Estas cajas poseen un tamaño mayor que las de una sola línea y muestran una barra de des- plazamiento hacia el margen derecho de la caja, permitiéndole al usuario desplazarse por el texto escrito. Para lograr esto, deberemos agrandar el tamaño de la caja de texto tanto como creamos necesario y configurar el atributo VerticalScrollBarVisibility con el valor Visible. Esta acción mostrará la barra de desplazamiento de manera constante, sin importar si el texto escrito sobrepasa la capacidad de la caja de texto. TextBox Text=”” AcceptsReturn=”True” TextWrapping=”Wrap” Margin=”8,8,53,68” VerticalScrollBarVisibility=”Visible” /TextBox 4. XAML AL EXTREMO 128 04_Silverlight.qxp 9/30/09 1:31 PM Page 128
  • 131.
    Otra propiedad queaparece en el código es AcceptReturn (aceptar retornos de carros). Este atributo permite que, si el usuario presiona la tecla INTRO o ENTER, el control re- fleje esta acción y genere saltos de línea. La Figura 34 muestra dos controles TextBox configurados con las propiedades antes listadas, donde el que se encuentra en la par- te inferior aplica el atributo TextWrapping con el valor NoWrap, que al utilizarlo en com- binación con el atributo HorizontalScrollBarVisibility mostrará además una barra de desplazamiento en la parte inferior del control TextBox, esperando que el usuario pre- sione la tecla INTRO o ENTER como condición para enviar el texto a la siguiente línea. Figura 34. Controles TextBox con la posibilidad de presentar barras de desplazamiento basadas en su contenido. TextBox Text=”” AcceptsReturn=”True” TextWrapping=”Wrap” Margin=”8,8,53,68” HorizontalScrollBarVisibility=”Visible” VerticalScrollBarVisibility=”Visible” /TextBox TextBox Text=”” AcceptsReturn=”True” Grid.Column=”0” Grid.Row=”1” TextWrapping=”NoWrap” Margin=”8,8,53,68” HorizontalScrollBarVisibility=”Visible” VerticalScrollBarVisibility=”Visible” /TextBox La asignación de información a estos controles, en especial los multilíneas, suele presentar cierta complejidad cuando se trata de manipular, en nuestro código, los Controles y componentes 129 04_Silverlight.qxp 9/30/09 1:31 PM Page 129
  • 132.
    retornos de carroy asignarlos al control. En el código siguiente, se utilizan los carac- teres de escape de C# para poder lograr este efecto. Como vemos, utiliza el carácter de escape n para conseguir asignar un retorno de carro en el texto enviado al control: private void Button_Click(object sender, RoutedEventArgs e) { this.TextoMultilinea.Text = “Texto largo multilínea con nretornos de carro”; } Al igual que los demás controles en Silverlight, el control TextBox también posee eventos que se dispararán bajo determinadas acciones del usuario. El más destaca- do es el evento TextChanged, que se disparará cada vez que el contenido del control (su texto) cambie de estado. Podemos declarar el evento de la siguiente manera: TextBox Margin=”8,58,8,52” x:Name=”TextBoxConEvento” TextChanged=”TextBox_TextChanged” Grid.Column=”1” Text=”” TextWrapping=”NoWrap” /TextBox En el código que hemos propuesto, el evento TextChanged es asociado al método TextBox_TextChanged del código C#. Este método, entonces, se ejecutará tantas ve- ces como el texto de la caja de texto se vea afectado por el usuario. private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { System.Diagnostics.Debug.WriteLine(this.TextBoxConEvento.Text); } En este ejemplo, cada vez que el usuario modifique el texto, éste se escribirá en la consola de depuración de Visual Studio 2008. Control PasswordBox PasswordBox es un control que extiende la funcionalidad del control TextBox con el objetivo de brindarnos la posibilidad de manipular contraseñas en nuestras aplica- ciones. El control PasswordBox está diseñado para representar todos los caracteres introducidos por el usuario por medio de una máscara, ocultando lo que éste es- criba y mostrando cada carácter introducido por medio de un punto de color negro. 4. XAML AL EXTREMO 130 04_Silverlight.qxp 9/30/09 1:31 PM Page 130
  • 133.
    Este control esmuy útil en aquellas aplicaciones donde el usuario deba introducir credenciales de validación, ya que éstas no deben ser mostradas a otros usuarios que pudieran estar mirando su pantalla en el momento de realizar esta acción. A conti- nuación, podemos ver el código XAML para declarar este control: PasswordBox x:Name=”[NombreDelControl]” Password=”[Contraseña a visualizar]” /PasswordBox Debido a que el control PasswordBox manejará contraseñas, el atributo de asig- nación y lectura del texto contenido se cambia por Password (contraseña). Si bien el carácter mostrado por defecto es el de un círculo negro, es posible modificar esto mediante el atributo PasswordChar, pudiendo aplicar cualquier otro carác- ter, que se usará por cada letra o número introducido por el usuario. El código siguiente muestra cómo configurar este atributo: PasswordBox PasswordChar=”-” / /Password El carácter elegido en el código anterior es el de un signo de resta, por lo que el control mostrará este elemento en lugar de los círculos de color negro tradicio- nales, como se observa en la siguiente figura. Figura 35. Signos de resta en lugar de círculos en el patrón del control PasswordBox. Controles y componentes 131 04_Silverlight.qxp 9/30/09 1:31 PM Page 131
  • 134.
    El control PasswordBoxtambién posee eventos comunes utilizados por todos los con- troles, pero, al igual que el control TextBox, PasswordBox tiene un evento en particular para capturar la modificación del estado del texto escrito en él. El evento en cuestión es PasswordChanged, y se comporta de igual forma que su homónimo TextChanged del control TextBox. Declaramos el evento PasswordChanged de la siguiente forma: PasswordBox PasswordChanged=”PasswordBox_PasswordChanged” PasswordChar=”-” /PasswordBox Como mencionamos, para acceder al contenido escrito en el control PasswordBox, deberemos usar la propiedad Password como vemos en el siguiente ejemplo: private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine(this.Password.Password); } El código propuesto anteriormente escribirá cada cambio del control en la con- sola de depuración de Visual Studio 2008. Control DataGrid En el capítulo 3, hemos hecho uso del control DataGrid para mostrar información en forma de filas y columnas. También vimos algunos atributos que permiten al usua- rio reordenar las columnas del control en tiempo de ejecución, cambiar el tamaño de las columnas y especificar diferentes colores para las filas mostradas. En este caso, iremos un poco más lejos, y mostraremos otras características del control. Primero, recordemos cómo declarar el control DataGrid en XAML. data:DataGrid /data:DataGrid Al agregar el control, podemos notar que Visual Studio sumará la referencia de System.Windows.Controls.Data a nuestra solución. Además, agregará una referencia en la cabecera de nuestro archivo para poder usar el control DataGrid. UserControl xmlns:data=”clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data” 4. XAML AL EXTREMO 132 04_Silverlight.qxp 9/30/09 1:31 PM Page 132
  • 135.
    Éste es elmotivo por el cual usamos data:DataGrid para declarar el control en nues- tro código. Podemos ver que el atributo xmlns genera una referencia al tipo data, indicándole desde dónde deberá consumir estos componentes. Figura 36. En el árbol de la solución (arriba a la derecha), podemos ver que Visual Studio 2008 agregó la referencia a System.Windows.Controls.Data. El control DataGrid tiene otras particularidades y, si bien en el ejemplo del capítulo 3 este control creó las columnas sobre la base de los datos, es posible que necesitemos manipular de diferentes maneras la construcción de estas columnas. Podríamos, por ejemplo, necesitar que en la edición de una columna específica, ésta se comporte de una forma particular. También podríamos necesitar inmovilizar una columna para que ésta no pueda variar su tamaño por más que el usuario así lo quiera. Para estas acciones, es posible utilizar Templates Columns (columnas plantilla). Estas co- lumnas permiten personalizar por completo cada columna y adaptarla a nuestras ne- cesidades. Veamos el siguiente código: data:DataGrid AutoGenerateColumns=”False” x:Name=”MiDataGrid” data:DataGrid.Columns data:DataGridTemplateColumn Header=”Fecha” data:DataGridTemplateColumn.CellTemplate DataTemplate TextBlock Text=”{Binding FechaNacimiento}”/ /DataTemplate /data:DataGridTemplateColumn.CellTemplate /data:DataGridTemplateColumn /data:DataGrid.Columns /data:DataGrid Controles y componentes 133 04_Silverlight.qxp 9/30/09 1:31 PM Page 133
  • 136.
    4. XAML ALEXTREMO 134 En el código que aparece en la página anterior, podemos ver algunos nuevos tags usados para definir nuestras columnas. Veamos en detalle cada uno. • data:DataGrid.Columns: este tag representa el contenedor para todas las colum- nas que crearemos por nuestra cuenta. • data:DataGridTemplateColumn: representa una columna tipo plantilla. Sobre la base de esta plantilla, todas las filas bajo esta columna tendrán el aspecto de- finido por la plantilla. • data:DataGridTemplateColumn.CellTemplate: este tag es el que representa el con- tenido de la celda de la plantilla. En él, podremos colocar otro control Silverlight, que será usado para representar el dato de la fila en esa columna. • {Binding Columna}: al momento de asignar una fuente de datos al DataGrid, todos los elementos que presenten el patrón {Binding} enlazarán los datos desde la fuen- te de datos y lo asignarán al atributo del control contenido por la plantilla. El nom- bre seguido de Binding representa el nombre de la columna en la fuente de datos. Podemos enlazar los datos desde una lista de entidades como la siguiente: public class Personas { public string Nombre { get; set; } public string Apellido { get; set; } RRR Los caracteres de escape son códigos especiales para representar elementos que, típicamente, no se pueden generar en cadenas de texto. Algunos de los caracteres más usados son: n para retornos de carro; para agregar una barra invertida; ” para agregar una comilla doble; ’ pa- ra agregar una comilla simple. CARACTERES DE ESCAPE 04_Silverlight.qxp 9/30/09 1:31 PM Page 134
  • 137.
    public DateTime FechaNacimiento { get; set; } publicbool EnviarRegalo { get; set; } } Podemos notar, en el código anterior, que la propiedad FechaNacimiento es del tipo DateTime, así como EnviarRegalo es del tipo bool. Esto puede ser importante conocerlo ya que, según el tipo de datos, podremos utilizar un control Silverlight específico para representar el valor en el DataGrid. En la Figura 37, observamos cómo, al enlazar los datos, la única columna mostrada es la definida anteriormente. Figura 37. DataGrid mostrando una columna creada en forma manual. Podemos crear y enlazar los datos con el siguiente código. public Page() { Controles y componentes 135 04_Silverlight.qxp 9/30/09 1:31 PM Page 135
  • 138.
    InitializeComponent(); LlenarGrilla(); } private void LlenarGrilla() { ListPersonaspersonas = new ListPersonas(); for (int i = 0; i 10; i++) { personas.Add(new Personas() { Nombre = “Nombre” + i.ToString(), Apellido = “Apellido” + i.ToString(), EnviarRegalo = ((i % 2) == 0 ? true : false), FechaNacimiento = DateTime.Now.AddDays(i)}); } this.MiDataGrid.ItemsSource = personas; } Para mostrar la propiedad EnviarRegalo de la clase Personas, podríamos, usar un con- trol CheckBox, asociando el atributo IsChecked al valor de esta propiedad. data:DataGridTemplateColumn Header=”Regalo” data:DataGridTemplateColumn.CellTemplate DataTemplate CheckBox IsEnabled=”False” IsChecked=”{Binding EnviarRegalo}” /CheckBox /DataTemplate /data:DataGridTemplateColumn.CellTemplate /data:DataGridTemplateColumn 4. XAML AL EXTREMO 136 RRR Es importante recordar que, si estamos trabajando con plantillas de columnas, debemos confi- gurar el atributo AutoGenerateColumns con el valor False para que no se generen las columnas de forma automática en el momento de enlazar los datos. Si olvidamos esto, las columnas se re- petirán, y la información no será consistente. COLUMNAS AUTOMÁTICAS 04_Silverlight.qxp 9/30/09 1:31 PM Page 136
  • 139.
    En este caso,la columna representará los valores de la fuente de datos en forma de control CheckBox como se ve en la figura que aparece a continuación. Figura 38. En este caso, se ha incorporado una nueva columna del tipo CheckBox para representar datos. Así como es posible crear nuestras propias columnas para mostrar la información, tam- bién podemos crear columnas con comportamiento para el momento de editarlas. /data:DataGridTemplateColumn.CellTemplate data:DataGridTemplateColumn.CellEditingTemplate DataTemplate basics:DatePicker SelectedDate=”{Binding FechaNacimiento, Mode=TwoWay}” / /DataTemplate /data:DataGridTemplateColumn.CellEditingTemplate /data:DataGridTemplateColumn Mediante el código anterior, es posible agregar una plantilla de columna para los casos en el que el usuario edite el contenido de la celda. También hay que notar que esta columna data:DataGridTemplateColumn.CellEditingTemplate debe estar dentro del tag data:DataGridTemplateColumn y dentro del conjunto de la co- lumna creada para asociar los datos en modo de vista que usamos al principio del ejemplo. En este caso, la columna de edición es utilizada para mostrar un control DatePicker y así poder manejar la fecha de nacimiento de una manera más práctica para el usuario, como se muestra en la Figura 39. Controles y componentes 137 04_Silverlight.qxp 9/30/09 1:31 PM Page 137
  • 140.
    Figura 39. Uncontrol DatePicker como plantilla para la edición de la celda. Otra característica importante es la de poder congelar columnas para que éstas no se vean afectadas por barras de desplazamiento. Pensemos en controles DataGrid con gran cantidad de columnas donde, para poder llegar hasta la última de éstas, es nece- sario recorrer cada una mediante el uso de barras de desplazamiento. Existirán ocasiones en las que sea necesario seguir visualizando las primeras columnas por más que nos desplacemos hasta el final del control DataGrid. Para lograr esto, de- beremos usar el atributo FrozenColumnCount, asignando la cantidad de columnas que se van a congelar. Desde nuestro código C#: this.MiDataGrid.FrozenColumnCount = 1; Como podemos ver en la Figura 40, la primera columna queda completamente inmóvil y no se ve afectada por la barra de desplazamiento. Por defecto, cada co- lumna tomará un tamaño, pero también es posible, mediante código, definir este comportamiento haciendo que las columnas del control DataGrid se adapten según diferentes factores por medio del atributo Width de cada columna, asignando co- mo posibles valores los que vemos a continuación: • Auto: al usar esta opción, la columna ajustará su tamaño en forma automática. • SizeToHeader: el tamaño será igual al largo del texto descriptivo de la columna. • SizeToCells: en este caso, el tamaño de la columna será igual al tamaño máximo contenido en cualquiera de las celdas de esta columna. • Valor numérico: colocando sólo un número, la columna será tan ancha como el valor numérico asignado. Este valor numérico es equivalente a pixeles. 4. XAML AL EXTREMO 138 04_Silverlight.qxp 9/30/09 1:31 PM Page 138
  • 141.
    Figura 40. Lacolumna que muestra la fecha de nacimiento de la persona está inmovilizada. Control Calendar El control Calendar nos permite manejar fechas de manera fácil. Por lo general, el manejo de fechas puede ser una tarea compleja, especialmente cuando necesi- tamos representar la misma fecha en diferentes idiomas. Para darnos una idea mediante un ejemplo simple, el patrón DD/MM/YYYY (día, mes, año), utiliza- do casi siempre en países de habla hispana, difiere del formato MM/DD/YYYY (mes, día, año), utilizado en países de habla inglesa. Este cambio, que a simple vista puede resultar trivial, a nivel de código puede ocasionar severos dolores de cabeza para el desarrollador, ya que implica convertir fechas de un formato a otro sobre la base de las configuraciones del usuario. Como podemos imaginar, este problema puede acrecentarse aún más en am- bientes de aplicaciones orientadas a la Web, debido a que éstas pueden ser acce- didas desde todos los países del globo, donde cada usuario utiliza un formato de fechas diferente del nuestro. Imaginemos lo complejo que resultaría tener que analizar en forma manual cada entrada de un usuario para poder saber la fecha exacta que quiso introducir. En el código que aparece a continuación vemos la declaración de un control Calendar en XAML: basics:Calendar /basics:Calendar Es necesario recordar que el prefijo basics: es tomado de la declaración de los con- troles en la cabecera de nuestro archivo XAML. Esto indica que el control Calendar Controles y componentes 139 04_Silverlight.qxp 9/30/09 1:31 PM Page 139
  • 142.
    también se encuentraincluido en la referencia System.Windows.Controls de las li- brerías de clases de Microsoft .Net para Silverlight. UserControl xmlns:basics=”clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls” El control Calendar posee varios atributos importantes que hacen a su configu- ración, pudiendo variar la forma de presentar el calendario así como los tipos de selección de las fechas. Veamos a continuación estos atributos y sus valores. DisplayMode Esta propiedad representa la forma en que será mostrado el calendario y sus fechas, pudiendo optar por alguno de los siguientes valores: • Month (mes): el calendario muestra todos los días correspondientes al mes selec- cionado, permitiendo desplazarse de mes en mes y seleccionar uno o más días. • Year (año): los elementos seleccionables del calendario serán los meses del año ele- gido, pero no se pueden seleccionar días. • Decade (década): muestra el calendario en formato de años, desplegando un conjun- to de años sin meses ni días. Es posible seleccionar un año o un rango de éstos. Figura 41. Control Calendar con los tres valores (Year, Decade y Month) posibles para el atributo DisplayMode. SelectionMode El atributo SelectionMode (modo de selección) hace referencia a la forma en có- mo el usuario podrá seleccionar una fecha en el control Calendar. Este atributo puede tomar los valores que se listan a continuación: 4. XAML AL EXTREMO 140 04_Silverlight.qxp 9/30/09 1:31 PM Page 140
  • 143.
    • None: elusuario no podrá seleccionar ninguna fecha del calendario. Esta opción es ideal para mostrar el calendario para solo lectura. • SingleDate: el usuario podrá seleccionar una única fecha del calendario. • SingleRange: con esta opción, el usuario podrá seleccionar un rango de fechas, pe- ro no podrá concatenarlas con otros rangos o fechas individuales. • MultiRange: esta selección de múltiples rangos de fechas permite al usuario selec- cionar rangos de fechas en intervalos. El usuario puede usar la tecla CTRL y el bo- tón del mouse para seleccionar más de una fecha o un rango de éstas. Figura 42. En el calendario de la izquierda, podemos ver cómo se han podido seleccionar múltiples fechas y rangos de fechas. Según las configuraciones regionales de cada país, es posible que necesitemos especificar el día que represente el inicio de la semana. Esto podemos lograrlo mediante el uso del atributo FirstDayOfWeek (primer día de la semana), pudien- do elegir cualquiera de los días incluidos en la semana mediante su nombre en inglés: Monday (lunes), Tuesday (martes), Wednesday (miércoles), Thursday (jueves), Friday (viernes), Saturday (sábado) y Sunday (domingo). El siguiente código apli- ca los atributos vistos hasta el momento: basics:Calendar x:Name=”MiCalendario” DisplayMode=”Year” FirstDayOfWeek=”Monday” IsTodayHighlighted=”True” SelectionMode=”MultipleRange” /basics:Calendar Este control también nos permite definir rangos de fechas que no puedan ser seleccionadas por el usuario. Esta acción suele ser usada en aplicaciones que ne- cesiten mostrar días no laborales, fechas disponibles para la selección o fechas ya Controles y componentes 141 04_Silverlight.qxp 9/30/09 1:31 PM Page 141
  • 144.
    seleccionadas que nodeban ser utilizadas por el usuario. Para lograr esto, debe- remos usar la propiedad BlackoutDates y asignar el rango de fechas por bloquear desde nuestro código C#. En este caso, se mostrará el rango de fechas desde el 6 de junio de 2009 hasta el 15 de junio de 2009 como fechas no seleccionables, public void ConfigurarCalendario() { this.MiCalendario.BlackoutDates.Add(new CalendarDateRange( new DateTime(2009, 6, 6), new DateTime(2009, 6, 15))); } Figura 43. El calendario de la izquierda muestra un rango de fechas que no podrán ser seleccionadas. Es posible agregar tantos rangos de fechas bloqueadas como necesitemos. Para esto será necesario agregar tantos atributos BlackoutDates como rangos bloqueados necesitemos. public void ConfigurarCalendario() { this.MiCalendario.BlackoutDates.Add(new CalendarDateRange( new DateTime(2009, 6, 6), new DateTime(2009, 6, 15))); this.MiCalendario.BlackoutDates.Add(new CalendarDateRange( new DateTime(2009, 6, 20), new DateTime(2009, 6, 28))); } 4. XAML AL EXTREMO 142 04_Silverlight.qxp 9/30/09 1:31 PM Page 142
  • 145.
    El código muestrados rangos de fechas bloqueadas dejando un pequeño rango de fechas posibles por seleccionar dentro de este rango. Figura 44. Podemos ver dos rangos de fechas bloqueadas en el calendario de la izquierda. Otra característica del control Calendar es la posibilidad de especificar la fecha por mostrar, así como acotar el límite de fechas que se van a mostrar a un rango deter- minado. Esto es útil si necesitamos mostrarle al usuario una fecha específica dife- rente de la fecha actual o si sólo queremos darle la posibilidad de seleccionar una fecha dentro de un rango de fechas, pero sin bloquear las no seleccionables, como vimos antes. Para posicionar el calendario en una fecha específica, deberemos usar, desde nuestro código C#, la propiedad DisplayDate del calendario, que hará que és- te se posicione en esa fecha. Los rangos de fechas a los que el usuario tendrá acceso podremos especificarlos con las propiedades DisplayDateStart y DisplayDateEnd. this.CalendarioDerecha.DisplayDate = new DateTime(2009, 07, 1); this.CalendarioDerecha.DisplayDateStart = new DateTime(2009, 07, 1); this.CalendarioDerecha.DisplayDateEnd = new DateTime(2009, 07, 29); Controles y componentes 143 RRR Existe en la Web una infinidad de recursos sobre Silverlight, tanto código de ejemplo como no- vedades sobre actualizaciones. Uno de los sitios que no podemos dejar de visitar es el de la biblioteca de clases Microsoft, que podemos encontrar en http://msdn.microsoft.com. MANTENERSE INFORMADO 04_Silverlight.qxp 9/30/09 1:31 PM Page 143
  • 146.
    En el códigopropuesto, el calendario mostrará como fecha el 1 de julio de 2009, limitando la selección de fechas a los rangos comprendidos entre la fecha ante- rior y el 29 de julio de 2009. En la Figura 45, podemos ver cómo este calendario muestra sólo este rango como única selección posible. Figura 45. El calendario que se encuentra a la derecha muestra sólo los valores especificados dentro del rango de fechas asignadas por código. Es posible también entregarle al usuario un calendario con fechas ya seleccionadas se- gún lo que establezcamos desde nuestro código C#. Para esto, debemos usar las pro- piedades SelectedDate cuando queramos seleccionar una única fecha, y SeletedDates cuando necesitemos seleccionar una o más fechas. En el código, podemos ver cómo se seleccionan fechas diferentes para generar una línea de selección como se ve en la Figura 46, que aparece en la pagina siguiente. this.MiCalendario.SelectedDate = DateTime.Now.AddDays(10); this.MiCalendario.SelectedDates.Add(DateTime.Now.AddDays(11)); this.MiCalendario.SelectedDates.Add(DateTime.Now.AddDays(12)); 4. XAML AL EXTREMO 144 RRR Cuando creamos plantillas para las columnas y, además, incluimos plantillas de edición de co- lumnas, es importante asegurarnos de agregar el atributo Mode con el valor TwoWay (dos vías). Si no lo hacemos, podríamos perder información, ya que la fuente de datos no se actualizaría con la acción de edición del usuario. MODOS EN EDICIÓN 04_Silverlight.qxp 9/30/09 1:31 PM Page 144
  • 147.
    Figura 46. Ademásde las fechas bloqueadas en el calendario de la izquierda, podemos ver un rango de fechas seleccionadas. Estas mismas propiedades pueden ser usadas para recolectar la fecha seleccionada. Teniendo en cuenta que, para asignar el valor hemos usado un tipo DateTime, al recuperarlo obtendremos también un tipo DateTime. La ventaja de esto es que no deberemos preocuparnos por el formato de fecha usado por el usuario. private void Button_Click(object sender, RoutedEventArgs e) { this.textoFecha.Text = “Fecha seleccionada: “ + this.CalendarioDerecha.SelectedDate.ToString(); } Figura 47. Al presionar el botón, éste muestra la fecha seleccionada en el calendario de la derecha. Controles y componentes 145 04_Silverlight.qxp 9/30/09 1:31 PM Page 145
  • 148.
    Como utilizamos SelectedDates,pudimos agregar un rango de fechas seleccionadas, por lo que deberemos utilizar esta misma propiedad para obtener aquellas fechas seleccio- nadas. Esta propiedad es útil cuando se conjuga con el uso del atributo SelectionMode, que ya hemos visto, porque, con él, podemos darle al usuario la posibilidad de especi- ficar más de una fecha; luego, necesitaremos algún mecanismo para poder capturar esas fechas. El código siguiente no realiza ninguna acción en especial, pero muestra cómo es posible capturar todas las fechas seleccionadas y almacenarlas en una colección de fechas. En la Figura 48, observamos cómo, en modo de depuración, inspeccionamos el resultado de la ejecución del código mostrando la lista de fechas seleccionadas. private void Button_Click_1(object sender, RoutedEventArgs e) { CollectionDateTime fechas = this.MiCalendario.SelectedDates; } Figura 48. Al inspeccionar la variable fechas, ésta nos muestra todas las fechas seleccionadas por el usuario en el control Calendar. El control Calendar, al igual que los demás controles, posee eventos que nos avisarán de los cambios realizados por el usuario. Los tres eventos principales listados en el código anterior son DisplayDateChanged, DisplayDatesChanged y DisplayModeChanged. Los dos primeros están relacionados con la selección de fechas por parte del usuario: mientras que DisplayDateChanged se disparará cada vez que el usuario seleccione una nueva fecha, DisplayDatesChanged se disparará cuando el usuario modifique el rango de fechas seleccionadas. Por otro lado, DisplayModeChanged se disparará cuando el modo de presentación del calendario (Month, Year, Decade) sea alterado. 4. XAML AL EXTREMO 146 04_Silverlight.qxp 9/30/09 1:31 PM Page 146
  • 149.
    basics:Calendar DisplayDateChanged=”Calendar_DisplayDateChanged” DisplayModeChanged=”Calendar_DisplayModeChanged” SelectedDatesChanged=”Calendar_SelectedDatesChanged” DisplayMode=”Decade”/ Control DatePicker El controlDatePicker es una extensión del control Calendar que vimos antes. Este con- trol extiende la funcionalidad del calendario agregando una caja de texto para que el usuario pueda escribir en ella una fecha sin tener que navegar en el calendario para poder seleccionarla. Además, este control suele ocupar menos espacio al desplegar el calendario cuando el icono de calendario a la derecha de la caja de texto es seleccio- nado, ocultándolo una vez que la fecha fue seleccionada. La declaración es: basics:DatePicker /basics:DatePicker Como este control es la unión de funcionalidades de un control Calendar y un control TextBox, las propiedades y eventos aplicados al control DatePicker son las mismas que las aplicadas al control Calendar. Podemos especificar fechas bloqueadas, día de inicio de la semana, fechas seleccionadas por defecto, así como reducir la cantidad de fechas navegables por el usuario. De igual forma, los eventos relacionados con este control pueden ser copiados de los eventos usados por el control Calendar. Este control agrega un nuevo atributo específico: SelectedDateFormat, que permite configurar la forma en la que se mostrará la fecha seleccionada en la caja de texto. Las opciones son: • Long: fecha en formato largo. La caja de texto mostrará la fecha usando el nombre del día y el nombre del mes seleccionado, generando una fecha larga. • Short: fecha en formato corto. La caja de texto utilizará el formato corto nu- mérico (dd/mm/yyyy) para mostrar la fecha seleccionada. Controles y componentes 147 , Los formatos en los que se pueden expresar las fechas varían de acuerdo al país del usuario. Por lo tanto, deberemos tener sumo cuidado al momento de manipular estos valores en aplica- ciones que puedan ser consumidas desde diferentes ubicaciones en el mundo. Más información en http://msdn.microsoft.com/es-es/. MANEJO DE FECHAS 04_Silverlight.qxp 9/30/09 1:31 PM Page 147
  • 150.
    Figura 49. Podemosver el control DatePicker de la izquierda con formato de fecha larga y a la derecha con formato de fecha corta. Control ProgressBar El control ProgressBar (barra de progreso) representa, típicamente, una línea que pue- de mostrar el progreso evolutivo de una cosa. Es común ver este tipo de controles en aplicaciones donde se cargan elementos de manera dinámica, mostrando el progreso de esta carga mediante una barra de progreso. La declaración XAML es: ProgressBar /ProgressBar Este control requiere de la configuración de dos atributos para especificar el valor mínimo y el valor máximo aceptados para desplegar la barra interna de progreso. • Minimum: este atributo representa el valor numérico mínimo que puede tomar la barra de progreso. Casi siempre, el valor es equivalente a 0 (cero). • Maximum: el valor máximo permitido que obtendrá la barra de progreso. Podemos colocar un valor tan elevado como fracciones internas queramos tener. Esto quiere decir que, si acumulamos valores para la barra de progreso avance de 10 en 10, y nuestro máximo es de 100, sólo veremos 10 intervalos en la barra de progresos. Si usamos un valor mayor o valores menores acumulativos, la barra de progresos se des- plazará con más suavidad por tener un rango mayor de intervalos. • Value: este atributo contiene el valor de la barra de progreso. Si asignamos un valor inicial diferente del valor mínimo establecido, la barra de progresos se mos- trará con información de progreso inicializada. 4. XAML AL EXTREMO 148 04_Silverlight.qxp 9/30/09 1:31 PM Page 148
  • 151.
    Controles y componentes 149 Podemosasignar los valores de la siguiente forma: ProgressBar Minimum=”0” Maximum=”100” Value=”50” x:Name=”MiProgressBar” /ProgressBar Figura 50. ProgressBar con progreso configurado. La propiedad Value es la que deberemos usar en nuestro código para poder asig- nar, en tiempo de ejecución, valores al control ProgressBar para que éste mues- tre el estado y el progreso de la acción realizada. Para entender este concepto, podemos simular un proceso de carga mediante la utilización de un cronómetro o Timer, y hacer que, por cada intervalo ejecutado por este cronómetro, el con- trol ProgressBar avance su barra de progreso. Storyboard _temporizador = new Storyboard(); public Page() { InitializeComponent(); _temporizador.Duration = TimeSpan.FromMilliseconds(10); _temporizador.Completed += new EventHandler(_temporizador_Completed); } private void _temporizador_Completed(object sender, EventArgs e) { if (this.MiProgressBar.Value this.MiProgressBar.Maximum) { 04_Silverlight.qxp 9/30/09 1:31 PM Page 149
  • 152.
    this.MiProgressBar.Value += 1; _temporizador.Begin(); } } privatevoid IniciarProgressBar() { this.MiProgressBar.Value = 0; _temporizador.Begin(); } private void Button_Click(object sender, RoutedEventArgs e) { IniciarProgressBar(); } Por cada intervalo de temporizador, el valor del control ProgressBar es incre- mentado en 1; esta acción se repite hasta que el valor actual de la barra de pro- greso sea igual al valor máximo disponible en el control ProgressBar configurado por medio de la propiedad Maximum. Otro atributo útil con el que cuenta el control ProgressBar es IsIndeterminate, que debemos utilizar cuando no sabemos con exactitud cuáles serán los valores del progreso por mostrar. Al configurar el atributo con el valor True (verdadero), el control mostrará un sinfín en la barra de progreso, que da a entender que se desconoce el estado actual de progreso. Figura 51. A la derecha, el control ProgressBar con el atributo IsIndeterminate aplicado. 4. XAML AL EXTREMO 150 04_Silverlight.qxp 9/30/09 1:31 PM Page 150
  • 153.
    También es posibleutilizar nuestro propio patrón visual para mostrar como barra de progreso. Como vemos en la Figura 52 que aparece debajo, utilizamos una ima- gen como elemento de progreso y no un elemento de color plano. Si agregamos un objeto del tipo ImageBrush dentro del tag ProgressBar.Foreground, cam- biamos el color sólido de la barra de progreso por la imagen seleccionada. ProgressBar Grid.Row=”1” Grid.Column=”0” Minimum=”0” Maximum=”100” Value=”60” Margin=”8,42,8,76” d:LayoutOverrides=”VerticalAlignment” ProgressBar.Foreground ImageBrush ImageSource=”http://www.redusers.com/wp- content/themes/redusers/images/logo.jpg”/ /ProgressBar.Foreground /ProgressBar Figura 52. En este ejemplo, el control ProgressBar usa una imagen como patrón para la barra de progreso. Controles y componentes 151 RRR Si bien hablamos de modos de ejecución y compilación, también existe el modo de depuración. A este modo accedemos, por lo general, al presionar la tecla F5 en nuestra aplicación. Este modo nos permitirá movernos línea a línea por nuestro código para poder depurarlo. MODO DE DEPURACIÓN 04_Silverlight.qxp 9/30/09 1:31 PM Page 151
  • 154.
    Control Slider Slider esun control conocido por los desarrolladores de aplicaciones de escritorio. Pue- de ser considerado una especie de potenciómetro, y al desplazar el medidor, el control informará el valor aplicado por el usuario. Podemos declararlo de la siguiente forma: Slider /Slider Algunos atributos del control Slider son similares al del control ProgressBar, pero agrega otros específicos, que vemos a continuación: • Minimum: al igual que con el control ProgressBar, este atributo representa el mí- nimo valor posible que obtendrá el control Slider. • Maximum: equivale al valor mayor posible que podrá obtener el control. • SmallChange: cuando el usuario desplaza la barra del control Slider, este valor representará el intervalo mínimo de esta acción. Así, si tenemos un valor equi- valente a 1, el control se desplazará en intervalos pequeños. Con valores mayores, los saltos serán equivalentes a este valor. • LargeChange: en el caso de que el usuario no utilice el botón para modificar el valor del control, sino que, por el contrario, presione sobre la barra del control Slider, es- ta acción hará que el acumulador salte según el valor especificado en esta propiedad. • Orientation: el control Slider puede visualizarse de dos formas, de manera horizon- tal o vertical. Esta orientación se define mediante los valores Horizontal y Vertical. Slider Minimum=”0” Maximum=”100” LargeChange=”10” SmallChange=”1” Orientation=”Vertical” /Slider Suscribiéndonos al evento ValueChanged, será posible disparar código cada vez que el usuario modifique los valores del control. Tomaremos el valor actual del control Slider mediante la propiedad Value. Slider x:Name=”MiSlider” ValueChanged=”Slider_ValueChanged” Minimum=”0” Maximum=”100” LargeChange=”10” SmallChange=”1” Orientation=”Vertical” /Slider 4. XAML AL EXTREMO 152 04_Silverlight.qxp 9/30/09 1:31 PM Page 152
  • 155.
    Figura 53. Eneste ejemplo, el control Slider se presenta de manera vertical. En nuestro código C#, tomaremos este valor para mostrarlo en la aplicación. Como resultado, cada vez que el usuario desplace la barra del control Slider, el control TextBlock tomará este valor y lo mostrará. private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgsdouble e) { this.textoSlider.Text = “Valor del Slider: “ + this.MiSlider.Value.ToString(); } Controles y componentes 153 … RESUMEN En este capítulo hemos visto los controles nativos de Silverlight y cómo implementarlos por medio de código XAML y desde C#. Si bien hemos podido interactuar con las principales propiedades de estos controles, aún queda mucho por delante ya que es posible mezclarlos y combinarlos de diferentes formas para obtener mejores interfaces visuales. Este capítulo es una guía de referencia sobre los controles Silverlight, y, en los capítulos siguientes, utiliza- remos lo que hemos visto aquí. 04_Silverlight.qxp 9/30/09 1:31 PM Page 153
  • 156.
    154 PREGUNTAS TEÓRICAS 1 ¿XAMLpuede ser interpretado por siste- mas no Microsoft? 2 ¿Cuál es el problema principal entre las in- terfaces para distintas plataformas? 3 ¿Cómo ayuda el código XAML en la posibi- lidad de transportar las interfaces entre distintas plataformas? 4 ¿Cuántas maneras de cerrar elementos XAML existen? 5 ¿En qué categorías podemos agrupar los controles XAML? 6 ¿Es posible tener más de un control conte- nedor como raíz del documento XAML? 7 ¿Es posible que el usuario desplace las co- lumnas y filas de un control Grid sin nece- sidad de generar código? 8 ¿Se pueden crear nuevos controles me- diante la conjunción de dos o más contro- les XAML? 9 ¿Qué contiene un archivo con extensión XAP? 10¿Qué atributo en los controles contenedo- res de texto deberemos usar para obtener el valor introducido por el usuario? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Cree dos grupos de controles RadioButton. Intente que cada grupo trabaje de forma independiente haciendo que la elección de un control en un grupo no afecte el ele- mento seleccionado en el segundo grupo. 2 Los controles pueden ser creados desde código XAML. Intente crear un conjunto de controles, pero desde código C#. 3 Habiendo agregado diferentes elementos dentro de un control contenedor, recorra cada uno de los elementos contenidos y modifique sus valores desde código C#. 4 Ingrese en el sitio web de UXity (www. uxity.com) para obtener ejemplos y mate- rial sobre Silverlight en castellano. 5 Transforme un control HyperlinkButton pa- ra que éste sea una imagen y no un texto. 04_Silverlight.qxp 9/30/09 1:31 PM Page 154
  • 157.
    Luz, cámara, acción Mover objetos156 Transformaciones 158 Transformación de traslación 159 Transformación de rotación 161 Transformación escalar 165 Transformación de distorsión 167 Aplicar todas las transformaciones 168 Animaciones 170 DoubleAnimation 171 ColorAnimation 173 Animaciones y transformaciones 175 Estilos y plantillas 178 Estilos 178 Plantillas 182 Resumen 185 Actividades 186 Capítulo 5 La forma de presentar la información no se reduce a colocar controles en posiciones específicas, sino a la habilidad de poder presentar esta información de la mejor manera y con el mayor dinamismo posible. En este capítulo veremos cómo agregar el factor dinámico a nuestras aplicaciones, mediante el uso de animaciones y comportamientos. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 05_Silverlight.qxp 9/30/09 1:32 PM Page 155
  • 158.
    MOVER OBJETOS En loscapítulos anteriores, hemos usado Silverlight para desplegar información des- de fuentes de datos, permitiendo al usuario interactuar con éstos. Podríamos decir que, de alguna forma, hemos creado interfaces de la manera tradicional, colocando controles en un espacio bidimensional, tratando de llenar el espacio especificado pa- ra la interfaz de la mejor forma posible. Y cuando hacemos referencia a la mejor for- ma posible, en realidad queremos decir que, muchas veces, las aplicaciones tratan de ocupar por completo cualquier espacio disponible de la superficie de la interfaz, co- locando botones o cualquier otro tipo de controles allí donde exista un espacio en blanco. Esto se debe al hecho de que, con el avance de la tecnología y de la infor- mación en general, cada vez más las aplicaciones de software necesitan mostrar ma- yor cantidad de datos en pantalla, ya que el usuario requiere ver más información al mismo tiempo sin tener que navegar entre diferentes ventanas o pulsar varios boto- nes para conseguir lo que le interesa. Por otro lado, tener que moverse de un lado al otro, y abrir y cerrar ventanas, muchas veces trae como consecuencia que datos im- portantes queden ocultos por las nuevas ventanas, y se llegue al punto en el que el usuario olvide por completo el porqué de la búsqueda inicial. Este tipo de desarrollo se propagó, en especial, por la falta de soporte de los sistemas operativos y por la com- plejidad de desarrollo de los variados lenguajes de programación usados para crear las diferentes aplicaciones. En muchos casos, las interfaces de las aplicaciones, por estas restricciones, llegan a presentarse como la que podemos ver en la siguiente figura. Figura 1. Una interfaz sobrecargada es poco práctica para el usuario. Existen diferentes formas de mejorar la experiencia del usuario en nuestras apli- caciones, así como también es posible optimizar el espacio de nuestra aplicación 5. LUZ, CÁMARA, ACCIÓN 156 05_Silverlight.qxp 9/30/09 1:32 PM Page 156
  • 159.
    para mostrar, deforma más natural para el usuario, la información requerida. Si bien no es el objetivo de este libro hablar de estas técnicas, resulta importante man- tener este pensamiento en el momento de realizar el diseño de aplicaciones. De cual- quier manera, una de estas técnicas, cada vez más usada, es la de desplazar o mover objetos dentro del área de la interfaz de la aplicación. De esta forma, los elementos principales se mantienen todo el tiempo visibles, de manera constante, y dan paso a otros elementos creados a partir de la selección o interacción del usuario con los elementos más importantes. Por esto, el movimiento de objetos no resulta ajeno a Silverlight, que permite modificar los estados, formas, tamaños y posición de los di- ferentes controles mientras ejecutamos nuestra aplicación. Durante este capítulo, hablaremos de las características provistas por Silverlight para poder mejorar las in- terfaces de las aplicaciones por medio del uso de movimiento y modificación del comportamiento visual de los controles y de los componentes. Figura 2. Una vista de Microsoft Surface, que permite arrastrar y mover elementos al tocarlos con la mano. Mover objetos 157 RRR Una interfaz de usuario demasiado cargada ocasionará rechazo por parte de éste. Es necesario, siempre que podamos, dejar las interfaces lo más simples y claras posibles, incluso moviendo los elementos en la pantalla durante la ejecución y abriendo la menor cantidad posible de ven- tanas o elementos que obstruyan la visión de datos importantes. INTERFAZ DE USUARIO 05_Silverlight.qxp 9/30/09 1:32 PM Page 157
  • 160.
    Transformaciones Las transformaciones sonuno de los modificadores de objetos disponibles en Sil- verlight. Con ellas, es posible cambiar la apariencia y el comportamiento de los con- troles y componentes de la interfaz. Es posible rotarlos, escalarlos, distorsionarlos, modificar su posición relativa a un punto, así como invertir su posición vertical u ho- rizontal. Podemos ver, a continuación, la lista de transformaciones disponibles: • Transformación de traslación: esta transformación modifica la posición del objeto dentro del eje de coordenadas X e Y. Es útil para desplazar o ajustar el objeto en una coordenada específica en forma independiente de la posición dentro del contenedor. • Transformación de rotación: la transformación de rotación sirve para girar el objeto sobre la base de una cantidad de grados definida. Esta transformación otor- ga la libertad suficiente para amoldar controles típicamente horizontales y verti- cales, como botones y grillas de datos, entre otros, en posiciones no tradicionales. • Transformación escalar: una transformación escalar hace referencia a la posibi- lidad de modificar el tamaño o la escala del objeto Silverlight. Si aplicamos esta transformación, podremos agrandar o achicar el tamaño del objeto, incluido su contenido. Debido a que los controles y los componentes en XAML se forman según la conjunción de otros elementos, al aplicar esta transformación, Silverlight aplicará la misma a todos los elementos internos del objeto modificado, por lo que no tendremos que preocuparnos por las proporciones de esos elementos internos, ya que estos se ajustarán en forma proporcional a su contenedor. • Transformación de distorsión: la transformación de distorsión o la acción de sesgado permite torcer los objetos para el eje X e Y. Este mecanismo resulta ideal en aquellos casos en los cuales necesitemos simular elementos de tres di- mensiones en un ambiente bidimensional o si queremos generar algún tipo de perspectiva en los objetos. Debido a que es posible aplicar más de una transformación al mismo tiempo sobre un objeto, éstas pueden ser agrupadas dentro de un tag XAML común. El tag TransformGroup representa esta agrupación y deberemos usarlo como agrupa- dor de los otros tags representativos para cada transformación. 5. LUZ, CÁMARA, ACCIÓN 158 RRR Al aplicar una transformación a cualquier objeto, éste se redibujará en forma instantánea. Esto es por demás útil para generar animaciones en tiempo de ejecución en nuestra aplicación, ya que no necesitaremos de cálculos o de imágenes pregeneradas para conseguir el efecto deseado. TRANSFORMACIONES 05_Silverlight.qxp 9/30/09 1:32 PM Page 158
  • 161.
    Figura 3. Uncontrol DataGrid con diferentes transformaciones aplicadas. Las transformaciones, así como otros efectos en Silverlight, son generados en tiempo de ejecución y de manera dinámica. Esto resulta muy beneficioso en com- paración con otras tecnologías, ya que el tamaño del archivo de Silverlight creado resulta mucho más pequeño. Esto se debe a que no es necesario que se genere por cada efecto un nuevo elemento con el resultado del efecto. Si pensamos en una transformación sobre una imagen de tamaño considerable, por cada transforma- ción aplicada a ésta, se podría generar una nueva imagen con el nuevo resultado. Si se agregara cada una de ellas al archivo final, se acrecentaría su tamaño en una proporción equivalente al tamaño de la imagen por la cantidad de imágenes creadas. Al calcular los efectos en tiempo de ejecución, esto se evita, y así se mejora enor- memente la optimización en la utilización de recursos. Transformación de traslación La transformación de traslación es usada para desplazar o colocar un objeto en una posición en X y en Y dentro del lienzo de una aplicación. En la Figura 4, el rectángulo se encuentra por encima de la línea que divide las dos columnas de la grilla. Mover objetos 159 RRR Los controles de agrupación, como vimos en capítulos anteriores, pueden contener otros con- troles y manejarlos como un conjunto agrupado. Si necesitamos mover más de un control al mismo tiempo, es posible aplicar una transformación de traslación al contenedor de estos controles en lugar de hacerlo uno por uno. TRASLACIÓN EN AGRUPADORES 05_Silverlight.qxp 9/30/09 1:32 PM Page 159
  • 162.
    Figura 4. Elrectángulo se muestra desplazado en X y en Y. En el código de la Figura 4, podemos notar algunas cuestiones interesantes obte- nidas al haber aplicado la transformación. Grid x:Name=”LayoutRoot” Background=”White” ShowGridLines=”True” Grid.RowDefinitions RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ ColumnDefinition/ /Grid.ColumnDefinitions Rectangle Height=”30” Grid.Column=”0” Grid.Row=”0” VerticalAlignment=”Top” Fill=”#FFAF2727” Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5” Rectangle.RenderTransform TransformGroup TranslateTransform X=”150” Y=”150”/ /TransformGroup /Rectangle.RenderTransform /Rectangle /Grid Si bien hemos definido dos columnas y una fila en la grilla, y el rectángulo está po- sicionado en la primera columna y la primera fila de acuerdo con los atributos 5. LUZ, CÁMARA, ACCIÓN 160 05_Silverlight.qxp 9/30/09 1:32 PM Page 160
  • 163.
    Grid.Column y Grid.Row,debido a la transformación aplicada, éste se encuentra des- plazado 150 pixeles en el eje X y 150 pixeles en el eje Y. Transformación de rotación Con esta transformación, podremos rotar cualquier objeto. Aplicando la misma transformación al rectángulo anterior, obtenemos el resultado que observamos en la Figura 5. Para conseguir esta transformación debemos aplicar el siguiente código. Grid x:Name=”LayoutRoot” Background=”White” Rectangle Margin=”87,144,155,127” Fill=”#FF4366DE” Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5” Rectangle.RenderTransform TransformGroup RotateTransform Angle=”45”/ /TransformGroup /Rectangle.RenderTransform /Rectangle /Grid Figura 5. Un rectángulo rotado 45 grados a favor del reloj. RotateTransform posee dos atributos adicionales que resultan útiles para espe- cificar el punto de rotación. En el ejemplo anterior, el punto de rotación había sido especificado mediante el atributo RenderTransformOrigin, separando con una coma el punto de rotación en X y en Y. En este ejemplo, el punto de rotación se encuentra posicionado en el centro del objeto especificando 0.5 (50%) para X y Mover objetos 161 05_Silverlight.qxp 9/30/09 1:32 PM Page 161
  • 164.
    0.5 (50%) paraY. Como resultado, teniendo una copia del mismo rectángulo, pero con una rotación de 90 grados, éste gira sobre el punto central del elemento. Si bien podemos utilizar RenderTransformOrigin, también es válido utilizar los atributos CenterX y CenterY dentro del tag RotateTransform para realizar el mis- mo trabajo que el del atributo anterior. En la Figura 6, vemos los dos casos. En ellos, a un grupo de elementos, no se le especifica un punto de rotación, lo que causa que este punto sea el extremo superior izquierdo. Figura 6. Dos grupos de rectángulos con su centro de rotación modificado. Podemos ver en el siguiente código las diferencias aplicadas en cada caso. Rectangle Margin=”18,146,0,125” Fill=”#FF4366DE” Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5” HorizontalAlignment=”Left” Width=”158” Rectangle.RenderTransform TransformGroup RotateTransform Angle=”45”/ /TransformGroup /Rectangle.RenderTransform /Rectangle Rectangle Margin=”18,146,0,125” Fill=”#FF4366DE” Stroke=”#FF000000” HorizontalAlignment=”Left” Width=”158” Rectangle.RenderTransform TransformGroup RotateTransform Angle=”90” CenterX=”79” CenterY=”15”/ /TransformGroup 5. LUZ, CÁMARA, ACCIÓN 162 05_Silverlight.qxp 9/30/09 1:32 PM Page 162
  • 165.
    /Rectangle.RenderTransform /Rectangle Rectangle Margin=”0,86,26,0” Fill=”#FF4366DE”Stroke=”#FF000000” Width=”158” HorizontalAlignment=”Right” VerticalAlignment=”Top” Height=”29” Rectangle.RenderTransform TransformGroup RotateTransform/ /TransformGroup /Rectangle.RenderTransform /Rectangle Rectangle Margin=”0,86,26,0” Fill=”#FF4366DE” Stroke=”#FF000000” Width=”158” HorizontalAlignment=”Right” Height=”29” VerticalAlignment=”Top” Rectangle.RenderTransform TransformGroup RotateTransform Angle=”30”/ /TransformGroup /Rectangle.RenderTransform /Rectangle ... Un punto que debemos tener en cuenta sobre cuál de los dos atributos necesita- mos usar radica en la forma de calcular la posición del punto de rotación. Por su parte, RenderTransformOrigin utiliza un valor porcentual, siendo 1 equivalente a 100%. Si el valor de RenderTransformOrigin es equivalente a “1,1”, éste será igual a la esquina inferior derecha, mientras que “0,0” representará la esquina superior izquierda. Este método para especificar el punto de rotación puede resultar, en algunos casos, más fácil de calcular, en especial para deducir el centro de rota- ción, ya que éste es representado por el valor “0.5,0.5”. Sin embargo, podría ser complejo de calcular para puntos intermedios. Por otro lado, para el caso de CenterX y CenterY, se utilizan valores numéricos equivalentes al tamaño del objeto por rotar. Así, si el objeto ocupa 100 pixeles de ancho y 50 pixeles de alto, el valor para CenterX deberá ser de 50, mientras el valor para CenterY deberá ser de 25. Como ya dijimos, los controles y compo- nentes también pueden ser afectados por estas transformaciones. Ellos seguirán prestando la misma funcionalidad, pero, en lo visual, se desplegarán basados en su transformación. En la Figura 7, vemos cómo una serie de controles aplican la transformación de rotación sin perder funcionalidad. Mover objetos 163 05_Silverlight.qxp 9/30/09 1:32 PM Page 163
  • 166.
    Figura 7. Controlespara entrada de datos con transformación de rotación. En el siguiente código, vemos ambos controles. Button HorizontalAlignment=”Left” Margin=”0,45,0,0” VerticalAlignment=”Top” Content=”Aceptar” d:LayoutOverrides=”Width” RenderTransformOrigin=”0.5,0.5” Button.RenderTransform TransformGroup RotateTransform Angle=”-90”/ /TransformGroup /Button.RenderTransform /Button TextBox HorizontalAlignment=”Left” Margin=”-55,0,0,123” VerticalAlignment=”Bottom” Width=”158” RenderTransformOrigin=”0.5,0.5” Text=”” TextWrapping=”Wrap” d:LayoutOverrides=”Height” TextBox.RenderTransform TransformGroup RotateTransform Angle=”-90”/ /TransformGroup /TextBox.RenderTransform /TextBox Si bien los valores para el punto de rotación que hemos usado hasta el momento se aplican a la parte interna del objeto rotado, es posible utilizar valores que sobrepa- 5. LUZ, CÁMARA, ACCIÓN 164 05_Silverlight.qxp 9/30/09 1:32 PM Page 164
  • 167.
    sen los límitesdel objeto por rotar. De esta manera, conseguiremos que el eje de ro- tación quede fuera del objeto. Esto hará que el punto de rotación marque la posi- bilidad de rotación por sobre una circunferencia y permitirá que el elemento gire alrededor de este punto como si se tratase de una órbita en un punto específico. Transformación escalar La transformación escalar es útil para modificar el tamaño de los objetos, tanto en largo como en alto o en una escala para X como para Y, si trasladamos las di- mensiones a un eje XY. En la figura que vemos a continuación, podemos apre- ciar dos rectángulos con sus respectivas modificaciones. Figura 8. Dos rectángulos modificados por la transformación escalar. Los atributos utilizados para modificar la escala de los objetos son ScaleX y ScaleY, ambos usados dentro del tag ScaleTransform, que hace referencia a este tipo de trans- formación. Podemos ver el código utilizado para generar la Figura 8 a continuación. Rectangle Margin=”125,57,149,0” Fill=”#FF82D442” Stroke=”#FF000000” RenderTransformOrigin=”-0.008,0.967” Height=”30” VerticalAlignment=”Top” Rectangle.RenderTransform TransformGroup ScaleTransform ScaleX=”1.3” ScaleY=”1.3”/ /TransformGroup /Rectangle.RenderTransform /Rectangle Mover objetos 165 05_Silverlight.qxp 9/30/09 1:32 PM Page 165
  • 168.
    Rectangle Margin=”125,57,149,0” Fill=”#FF9FCE7A”Stroke=”#FF000000” Height=”30” VerticalAlignment=”Top”/ Rectangle Margin=”125,0,149,106” Fill=”#FF406225” Stroke=”#FF000000” Height=”30” VerticalAlignment=”Bottom” RenderTransformOrigin=”0.5,0.5” Rectangle.RenderTransform TransformGroup ScaleTransform ScaleX=”1.3” ScaleY=”1.3”/ /TransformGroup /Rectangle.RenderTransform /Rectangle Rectangle Margin=”125,0,149,106” Fill=”#FF293B1A” Stroke=”#FF000000” Height=”30” VerticalAlignment=”Bottom”/ ScaleX y ScaleY utilizan un valor numérico que representa el porcentaje de creci- miento que recibirá el objeto. En el ejemplo, utilizamos el valor 1.3, que represen- ta el 100% del tamaño original más un 30% adicional, por lo que el objeto habrá crecido 30%, tanto en X como en Y. Al igual que la transformación de rotación, la transformación escalar también hace uso de los atributos CenterX y CenterY, así como de RenderTransformOrigin, aplicando las mismas reglas antes mencionadas. En la Figura 9, podemos ver dónde está posicionado el eje de crecimiento para el rectángulo superior, el cual es cercano a la esquina inferior izquierda del objeto. El rectángulo inferior utiliza su centro como punto de crecimiento. Debido a es- to, vemos que este rectángulo crece hasta cubrir el rectángulo original, y lo hace desde su centro hacia las cuatro direcciones del eje XY. Figura 9. El rectángulo superior modifica su eje de crecimiento. 5. LUZ, CÁMARA, ACCIÓN 166 05_Silverlight.qxp 9/30/09 1:32 PM Page 166
  • 169.
    Transformación de distorsión Estaúltima transformación modifica la apariencia del objeto aplicando ángulos de torsión. Pensemos en un objeto de forma cuadrada o rectangular. Cada esquina de este objeto es representada por un ángulo de 90 grados. Esta transformación tiene el objetivo de modificar estos ángulos rectos sobre la base de un valor numérico ex- presado, también, en grados. En la siguiente figura, vemos cómo es distorsionada la apariencia de un objeto cuadrado. Figura 10. El objeto es distorsionado para generar una vista en perspectiva. En el código que aparece a continuación, podemos ver que los atributos AngleX y AngleY son configurados con los valores de -10 grados cada uno. Estos dos atri- butos, junto con RenderTransformOrigin, son los que le otorgan el aspecto final al objeto una vez distorsionado. Si modificamos el valor RenderTransformOrigin para que se encuentre fuera del centro del objeto, conseguiremos distorsiones no simétricas, que pueden ser úti- les, basadas en la perspectiva que queramos lograr. Rectangle Margin=”134,102,186,118” Fill=”#FF43A6C3” Stroke=”#FF000000” RenderTransformOrigin=”0.5,0.5” Rectangle.RenderTransform TransformGroup SkewTransform AngleX=”-10” AngleY=”-10”/ /TransformGroup /Rectangle.RenderTransform /Rectangle Mover objetos 167 05_Silverlight.qxp 9/30/09 1:32 PM Page 167
  • 170.
    Aplicar todas lastransformaciones Como mencionamos, es posible aplicar más de una transformación a nuestros ob- jetos, incluso, se pueden aplicar estas transformaciones a los controles para entrada de datos, así como para aquellos que despliegan la información. Para poner en prác- tica esto, extenderemos un poco el ejemplo creado en el capítulo 3, modificando la apariencia del control DataGrid, además de agregar algunos otros elementos llama- tivos a la interfaz creada para ese ejemplo. Figura 11. Resultado final después de haber aplicado transformaciones a los controles Silverlight. El primer paso, consiste en aplicar transformaciones a nuestro DataGrid, que estará ubicado en una de las dos columnas de la grilla contenedora. Además, el control DataGrid fue colocado dentro de un control Border para simular las puntas redondea- das, aplicándole un color degradado. Estos controles, finalmente, se encuentran den- tro de un control StackPanel. Sobre este StackPanel, aplicaremos las transformaciones. Grid x:Name=”LayoutRoot” Grid.RowDefinitions RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition Width=”0.512*”/ ColumnDefinition Width=”0.488*”/ /Grid.ColumnDefinitions Grid.Background 5. LUZ, CÁMARA, ACCIÓN 168 05_Silverlight.qxp 9/30/09 1:32 PM Page 168
  • 171.
    LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStopColor=”#FF2A77FF”/ GradientStop Color=”#FFFFFFFF” Offset=”1”/ /LinearGradientBrush /Grid.Background StackPanel HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch” Margin=”0,0,8,0” RenderTransformOrigin=”0.5,0” StackPanel.RenderTransform TransformGroup ScaleTransform ScaleY=”1”/ SkewTransform AngleY=”-28”/ RotateTransform/ TranslateTransform Y=”25”/ /TransformGroup /StackPanel.RenderTransform TextBlock FontFamily=”Arial” FontSize=”20” FontStyle=”Normal” FontWeight=”Bold” Text=”Registros disponibles” TextWrapping=”Wrap”/ Border BorderThickness=”1,1,1,1” CornerRadius=”10,10,10,10” BorderBrush=”#FF000000” Height=”450” Border.Background LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FF9BD3E8”/ GradientStop Color=”#FF2D88A9” Offset=”1”/ /LinearGradientBrush /Border.Background data:DataGrid BorderThickness=”0,0,0,0” HorizontalContentAlignment=”Center” VerticalContentAlignment=”Center” x:Name=”MiGrilla” Height=”400” HorizontalAlignment=”Center” VerticalAlignment=”Center” Width=”300”/ /Border /StackPanel Para mostrar la cantidad de registros seleccionados en cada búsqueda, usamos un control TextBlock con una transformación de rotación. TextBlock HorizontalAlignment=”Right” VerticalAlignment=”Bottom” Text=”Registros” TextWrapping=”Wrap” Grid.Column=”1” Mover objetos 169 05_Silverlight.qxp 9/30/09 1:32 PM Page 169
  • 172.
    d:LayoutOverrides=”HorizontalAlignment, Height” Margin=”0,0,- 172.962,76.866”RenderTransformOrigin=”0,1” Opacity=”0.5” FontSize=”48” FontFamily=”Lucida Sans Unicode” FontWeight=”Bold” FontStyle=”Normal” x:Name=”registros” Width=”318.554” TextBlock.RenderTransform TransformGroup ScaleTransform/ SkewTransform/ RotateTransform Angle=”-90”/ TranslateTransform Y=”76.23” X=”150.674”/ /TransformGroup /TextBlock.RenderTransform /TextBlock Luego, modificamos el código encargado de realizar las búsquedas sobre la base del tex- to introducido por el usuario para desplegar la cantidad de registros encontrados. private void Button_Click(object sender, RoutedEventArgs e) { var q = from c in productos where c.Nombre.Contains(this.buscador.Text) || c.Descripcion.Contains(this.buscador.Text) select c; this.MiGrilla.ItemsSource = q; this.registros.Text = “Registros “ + q.CountProducto().ToString(); } De esta manera, probamos que las transformaciones pueden ser no sólo aplicadas a formas básicas, sino a cualquier elemento creado por código XAML. Animaciones Como hemos notado con las transformaciones, éstas no generan nuevos ele- mentos del objeto modificado, sino que actúan sobre él en tiempo de ejecución de la aplicación Silverlight. Esto ahorra, por un lado, los recursos transmitidos hacia el cliente que visualiza nuestra aplicación, y por otro, nos da la posibilidad de modificar estas transformaciones en tiempo de ejecución, no atándonos a un guión establecido con anterioridad. Basadas en este modelo, las animaciones en 5. LUZ, CÁMARA, ACCIÓN 170 05_Silverlight.qxp 9/30/09 1:32 PM Page 170
  • 173.
    Silverlight se diferencianbastante de los modelos tradicionales de animación, que, por lo general, se representan mediante la creación de cuadros reproducidos en forma sucesiva. Este modelo, el del cuadro a cuadro, también resulta costoso en recursos de cara al usuario, ya que por cada cuadro es necesario transmitir cada uno de éstos como si se tratara de la reproducción de una película o de un dibujo ani- mado. Pero además, renace el problema de elementos guionados, que nos llevan a pensar en todas las posibles alternativas que los elementos de nuestra aplica- ción podrían tener. Por el contrario, Silverlight utiliza para las animaciones el mismo modelo que hemos visto en las transformaciones. Esto significa que po- dremos animar los distintos elementos de nuestra aplicación en tiempo de eje- cución, pudiendo alterar o generar nuevo contenido basado en las necesidades del usuario. A pesar de esto, es posible que la cantidad de animaciones que podamos generar con Silverlight parezcan limitadas, ya que el modelo reduce esta canti- dad a tres tipos de animaciones, los cuales tendrán la capacidad de modificar las propiedades y los atributos de los objetos por animar. • DoubleAnimation: este modelo de animación está orientado a modificar los valo- res numéricos de las propiedades y atributos del objeto. • ColorAnimation: este tipo de animación es utilizado para modificar valores que no pueden ser representados por números reales. Los colores, por ejemplo, suelen re- presentarse en hexadecimal. • PointAnimation: esta animación tiene la capacidad de modificar valores en propieda- des que trabajen con puntos. Este modelo de animación está fuertemente relaciona- do con movimientos de objetos y con el desplazamiento en el eje de coordenadas XY. DoubleAnimation Como dijimos, este modelo de animación es útil cuando queremos modificar los valores numéricos de las propiedades y atributos de cualquier objeto. Para declarar una animación de este tipo, podemos usar el siguiente código: DoubleAnimation From=”128” To=”200” Duration=”0:0:10”/ Los atributos From (desde) y To (hasta) determinarán los rangos entre los cuales el atributo por modificar se irá alternando. En el caso anterior, el valor en cuestión irá desde 128 a 200; estos valores se distribuirán de acuerdo con el tiempo especi- ficado por el atributo Duration (duración). Este último atributo es representado por los valores correspondientes a horas, minutos y segundos (hh:mm:ss). Para el ejem- plo, la animación tendrá una duración de 10 segundos. En la Figura 12, vemos cómo, al aplicar esta animación sobre la propiedad Width de un rectángulo, éste modifica su tamaño según dicha animación. Mover objetos 171 05_Silverlight.qxp 9/30/09 1:32 PM Page 171
  • 174.
    Figura 12. Elrectángulo en el navegador de la izquierda, antes de que ocurriese la animación; y el de la derecha, una vez ocurrida. Para lograr esto, lo primero que deberemos hacer es crear nuestro rectángulo. Grid x:Name=”LayoutRoot” Background=”White” Rectangle MouseEnter=”Rectangulo_MouseEnter” x:Name=”Rectangulo” Height=”55” HorizontalAlignment=”Left” Margin=”69,57,0,0” VerticalAlignment=”Top” Width=”128” Fill=”#FF407280” Stroke=”#FF000000” /Rectangle /Grid Una vez que tenemos el rectángulo en posición, deberemos crear la animación. UserControl.Resources Storyboard x:Name=”Animacion1” DoubleAnimation From=”128” To=”200” Duration=”0:0:01” Storyboard.TargetProperty=”Width” Storyboard.TargetName=”Rectangulo”/DoubleAnimation /Storyboard /UserControl.Resources Esta animación es considerada un recurso genérico de todo el control XAML, por este motivo, deberemos colocarla dentro del tag UserControl.Resources. 5. LUZ, CÁMARA, ACCIÓN 172 05_Silverlight.qxp 9/30/09 1:32 PM Page 172
  • 175.
    El siguiente tages el Storyboard. Este tag agrupará en un conjunto todas las ani- maciones que se van a aplicar a un mismo objeto o, si lo preferimos, animaciones para diferentes objetos que podremos ejecutar al mismo tiempo como un conjun- to. Es importante la presencia de un nombre para el tag Storyboard por medio del atributo x:Name, ya que de esta forma podremos iniciar la ejecución del conjunto de animaciones invocando su nombre. Los atributos del tag DoubleAnimation, Storyboard. TargetProperty y Storyboard.TargetName hacen referencia a la propiedad que esa animación modificará y al nombre del objeto que contiene la propiedad, res- pectivamente. Para este caso, Storyboard.TargetProperty hace referencia a la propiedad Width del objeto definido por Storyboard.TargetName, que en este caso es Rectangulo. Para activar la animación, es necesario especificar el momento en el cual ésta se ini- ciará. Esto lo logramos desde nuestro código C#, de la siguiente manera, donde animación es el nombre previamente configurado en el tag Storyboard: this.Animacion1.Begin(); ColorAnimation ColorAnimation es necesaria para animaciones que modifiquen el color de los obje- tos. Posee iguales atributos que los presentados en la animación del tipo DoubleAnimation y, para usarla, deberemos declararla como sigue: ColorAnimation/ColorAnimation Figura 13. A la derecha, el rectángulo presenta un cambio de color, el mismo que fue aplicado en forma paulatina con la animación. Mover objetos 173 05_Silverlight.qxp 9/30/09 1:32 PM Page 173
  • 176.
    La declaración completade esta animación podemos verla a en el siguiente código, que pasa del color original del rectángulo hasta el color negro definido por el atri- buto To. En este caso, modificamos la propiedad Fill, y su atributo Color.Storyboard. TargetProperty hace referencia a este conjunto de propiedades y atributos. ColorAnimation From=”#FF407280” To=”#FF000000” Duration=”0:0:01” Storyboard.TargetProperty=”(Fill).(Color)” Storyboard.TargetName=”Rectangulo”/ColorAnimation PointAnimation PointAnimation es el último de los modelos de animación propuestos por Silverlight. Puede ser usado para modificar puntos de coordenadas XY. Para declarar esta ani- mación, debemos hacerlo de la siguiente manera: PointAnimation/PointAnimation Para graficar este modelo de animación, crearemos un círculo que desplazaremos sobre la base de su centro de dibujo. Podemos declarar este elemento como sigue: Path Fill=”#FF407280” MouseEnter=”Path_MouseEnter” Path.Data EllipseGeometry x:Name=”GeometriaCircular” Center=”200,200” RadiusX=”40” RadiusY=”40” / /Path.Data /Path Figura 14. Este círculo se desplazará sobre la base de su centro de dibujo. 5. LUZ, CÁMARA, ACCIÓN 174 05_Silverlight.qxp 9/30/09 1:32 PM Page 174
  • 177.
    La animación porpuntos la declararemos dentro de su propio tag Storyboard, el cual modificará el atributo Center del círculo creado. Storyboard x:Name=”Animacion2” PointAnimation From=”0,200” To=”300,200” Duration=”0:0:2” Storyboard.TargetName=”GeometriaCircular” Storyboard.TargetProperty=”Center” /PointAnimation /Storyboard Debido a que se trata de un punto en el mapa de coordenadas, tanto el atributo From como To presentan el patrón XY separados por una coma. Al aplicar esta ani- mación, veremos que el círculo se desplazará de izquierda a derecha cubriendo 300 pixeles de distancia en 2 segundos. Como ya hemos podido notar, los atributos de configuración para las animaciones son los mismos entre los modelos, y existen otros elementos comunes para estas animaciones que pueden ser de utilidad. • RepeatBehavior: este atributo dictamina la cantidad de veces que la animación se repetirá una vez que llegue a su fin. Podemos configurar para que se repita una cantidad de veces determinada usando un valor numérico, o la palabra Forever (para siempre), para que la animación sea continua. • AutoReverse: es posible optar entre True (verdadero) o False (falso). Si configuramos esta propiedad en True, la animación retrocederá sobre sus pasos una vez finalizada. • SpeedRatio: este atributo representa la velocidad en la animación. Por defecto, el valor utilizado es 1, lo que quiere decir que la animación trabajará a velocidad nor- mal. Si incrementamos este valor a 2, la animación será dos veces más rápida que la velocidad normal. Este valor no es relación de cuadros por segundo, sino la ra- pidez o lentitud con las que avanzará y concluirá la animación. Así, si tenemos una animación con una duración de 5 segundos y configuramos el valor de este atributo a 2, la animación debería concluir en 2 segundos y medio, pero, si el va- lor es equivalente a 0.5, la animación tardaría el doble. • BeginTime: representa un lapso de tiempo que la animación esperará antes de iniciarse. Este lapso es representado de igual forma que el del atributo Duration, mediante la nomenclatura hh:mm:ss. Animaciones y transformaciones Con un poco de imaginación, veremos que la combinación de animaciones con los atributos de los controles nos puede dar suficiente libertad como para hacer casi todo lo que necesitemos. Podríamos por ejemplo, conjugar animaciones con las transfor- maciones vistas al principio de este capítulo para conseguir no sólo modificar tamaños, colores o posiciones de los objetos, sino también poder cambiar de aspecto, rotarlo, Mover objetos 175 05_Silverlight.qxp 9/30/09 1:32 PM Page 175
  • 178.
    distorsionarlo o agrandarloa gusto. Para graficar esto, utilizaremos un objeto al cual le aplicaremos una animación para una transformación de rotación. Figura 15. Animando una transformación de rotación. El primer paso consiste en declarar el objeto con los valores de la transformación. Es importante tener estos valores por defecto ya que, de no existir, no podrían ser encontrados por el elemento que genera la animación. Rectangle Height=”29” VerticalAlignment=”Top” Margin=”149,83,116,0” Fill=”#FFBF3434” MouseEnter=”Rectangle_MouseEnter” Rectangle.RenderTransform RotateTransform Angle=”” x:Name=”anguloRectangulo”/RotateTransform /Rectangle.RenderTransform /Rectangle También podemos ver que el elemento RotateTransform tiene un atributo x:Name, lo que hará que sea mucho más simple poder acceder a él desde la animación y no tener que crear cadenas de texto largas para indicar cuál es el atributo sobre el que actuará la animación. Por último, creamos la animación para esta transformación: Storyboard x:Name=”Animacion” DoubleAnimation From=”0” To=”90” 5. LUZ, CÁMARA, ACCIÓN 176 05_Silverlight.qxp 9/30/09 1:33 PM Page 176
  • 179.
    Storyboard.TargetName=”anguloRectangulo” Storyboard.TargetProperty=”Angle”/DoubleAnimation /Storyboard La animación seaplicará sobre el atributo Angle (ángulo), aplicándole grados que pueden ir desde 0 a 90. Para dar inicio a esta animación, deberemos escribir el código que vemos a continuación: private void Rectangle_MouseEnter(object sender, MouseEventArgs e) { this.Animacion.Begin(); } Figura 16. Podremos aplicar este tipo de transformaciones a cualquier elemento. En este caso, animamos un control DatePicker mediante una transformación de rotación. Mover objetos 177 _` Debido a que podemos definir líneas sinusoidales, las cuales cuentan con puntos XY de inicio y puntos XY de finalización además de un radio de curva, es posible usar PointAnimation para ani- mar esta curva en tiempo de ejecución para lograr efectos de ondas. ANIMAR CURVAS 05_Silverlight.qxp 9/30/09 1:33 PM Page 177
  • 180.
    Estilos y plantillas Enla mayoría de los casos, usamos los controles provistos por Silverlight tal como son, sin modificar su apariencia visual predefinida. Esto puede ser útil en muchos casos, pe- ro existirán muchas ocasiones en las que deberemos adaptar estos elementos a nuestros diseños, y modificar las propiedades visuales de los componentes. Para lograr esto, so- lemos cambiar la apariencia visual control por control, algo que consumirá tiempo y será costoso, además de generar código XAML innecesario, agrandando el tamaño de nuestra aplicación y haciéndola mucho más complicada de modificar y mantener. Ima- ginemos que nuestra aplicación cuenta con veinte botones y que, después de haber mo- dificado y terminado nuestro trabajo, nos encontramos con un nuevo requerimiento que implica tener que volver a cambiar el aspecto de estos botones. Hacer este cambio nos resultará un esfuerzo extremadamente costoso. Para solucionar el problema, debe- mos hacer uso de estilos. Estos estilos trabajan de manera similar a las hojas de estilo (CSS, Cascade Style Sheets) de HTML, donde podremos definir un comportamiento visual general para los controles y aplicarlos a todos los controles que necesitemos. Así, al modificar un estilo, es posible afectar a todos los controles que consuman de éste. Lasplantillasomoldes,porotraparte,sonutilizadospararedefinirelcomportamiento, como la apariencia visual sobre la base de un control inicial, pero la redefinición de la apariencia visual va mucho más allá que la conseguida con estilos. Mientras que con estilos podemos modificar las características tales como color, ancho, alto, o tipo de fuente usada en el control, con las plantillas podremos hacer que, por ejemplo, un botón no tenga la apariencia de un botón como tal, sino que, por el contrario, se transforme en un círculo, en una imagen o en cualquier otro elemento que es- té acorde a nuestras necesidades visuales. Estilos Luego de lo dicho anteriormente, veremos cómo modificar la apariencia visual de los controles con la creación y aplicación de estilos a los controles ya existentes. Pa- ra poder declarar un estilo, debemos seguir el siguiente patrón: UserControl.Resources Style x:Key=”Estilo1” TargetType=”TextBox” ... /Style /UserControl.Resources Podemos ver que el estilo es declarado dentro de los recursos del tag UserControl de la misma forma que hicimos con las animaciones y el tag Storyboard. Si bien ésta es una opción, también podríamos declarar este estilo en los recursos globales de toda la aplicación, colocándolo dentro del archivo App.xaml. 5. LUZ, CÁMARA, ACCIÓN 178 05_Silverlight.qxp 9/30/09 1:33 PM Page 178
  • 181.
    Application.Resources Style x:Key=”Estilo1” TargetType=”TextBox” ... /Style /Application.Resources Deesta forma, si tenemos más de una página XAML en nuestra aplicación, po- dremos compartir el estilo entre ellas. Por otro lado, también vemos que aparecen dos nuevos atributos en la declaración de un estilo. • x:Key: este atributo es necesario para poder identificar el estilo creado. Consumi- remos el estilo mediante este nombre. • TargetType: tipo de control que podrá usar este estilo. Con este atributo, restringimos el uso del estilo a un tipo de control. Es similar a la capacidad de ASP.net de gene- rar estilos visuales para los controles, pudiendo crear estilos para tipos específicos. Figura 17. Varios TextBox que consumen del mismo estilo. Mover objetos 179 En la Web, podemos encontrar cientos de sitios con código de ejemplo para Silverlight 2. De cual- quier manera, uno de los destacados es el sitio oficial de Silverlight, hasta el que podemos na- vegar para descargar excelentes ejemplos. La dirección es http://silverlight.net. CÓDIGO DE EJEMPLO 05_Silverlight.qxp 9/30/09 1:33 PM Page 179
  • 182.
    Los estilos seaplican a cada una de las propiedades del objeto que queremos confi- gurar. En el caso de la Figura 17, el estilo utilizado es el siguiente: Style x:Key=”Estilo1” TargetType=”TextBox” Setter Property=”Background” Setter.Value LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FF88CAF0”/ GradientStop Color=”#FFFFFFFF” Offset=”1”/ /LinearGradientBrush /Setter.Value /Setter Setter Property=”BorderBrush” Setter.Value LinearGradientBrush EndPoint=”0.5,1” StartPoint=”0.5,0” GradientStop Color=”#FFA3AEB9”/ GradientStop Color=”#FF9DBACE” Offset=”0.567”/ GradientStop Color=”#FF000000” Offset=”1”/ /LinearGradientBrush /Setter.Value /Setter Setter Property=”Foreground” Value=”#FF342449”/ Setter Property=”BorderThickness” Value=”2,2,2,2”/ Setter Property=”MinHeight” Value=”25”/ Setter Property=”Text” Value=””/ /Style Necesitamos colocar, por cada atributo por modificar, un tag Setter, el mismo que especifica el nombre de la propiedad (Property) que se modificará y su valor (Value). Es posible también especificar valores para tipos complejos mediante el uso de Setter. Value, colocando dentro de éste la descripción del tipo complejo. Por último, debe- remos aplicar el estilo al control que lo consumirá de la siguiente manera: TextBox Height=”25” Width=”120” Style=”{StaticResource Estilo1}”/ Si colocamos los estilos dentro de la declaración del tag UserControl como den- tro del tag Application, es posible reutilizarlos de forma global, aunque también 5. LUZ, CÁMARA, ACCIÓN 180 05_Silverlight.qxp 9/30/09 1:33 PM Page 180
  • 183.
    pueden reducir elalcance de los estilos limitándolos al control en sí o a un con- junto de controles contenidos por algún control contenedor. En la Figura 18, el botón de la derecha está contenido por un control StackPanel, que tiene declarado el estilo para el botón, estilo que sólo podrá ser consumido por los controles contenidos por el StackPanel. La declaración del estilo en el StackPanel es similar a la utilizada de manera global por el tag UserControl co- mo el tag Application dentro del archivo App.xaml. StackPanel Margin=”171,12,24,71” StackPanel.Resources Style x:Key=”EstiloContenido” TargetType=”Button” Setter Property=”BorderThickness” Value=”2,2,2,2”/ Setter Property=”Background” ... Figura 18. El botón de la derecha, contenido por un StackPanel consumiendo el estilo declarado. Mover objetos 181 RRR Tratando de mantener concordancia entre desarrollos, los estilos poseen un comportamiento similar a las máscaras usadas en ASP.net. Esto garantiza que los desarrolladores web puedan fácilmente adaptarse a este modelo. Más información en http://msdn.microsoft.com/es-es, buscando temas y máscaras. EL ENFOQUE ASP.NET 05_Silverlight.qxp 9/30/09 1:33 PM Page 181
  • 184.
    Plantillas Si el estilonos permitió modificar los valores, atributos y propiedades visuales del control, las plantillas nos permitirán crear controles basándonos en otros y alterar el aspecto de éstos. La ventaja significativa de las plantillas radica en que, utilizando como raíz un control existente y pudiendo reusar sus eventos, podre- mos crear uno nuevo. Pensemos en la capacidad de un botón de disparar un even- to cuando el usuario lo presiona con el mouse. Esta capacidad no está presente en todos los controles, por lo que podríamos reutilizarla creando nuestro propio botón con un aspecto diferente del estándar. De esta forma, partiendo de un con- trol inicial, construimos uno completamente nuevo. Figura 19. Un nuevo botón construido sobre la base del control estándar. Button HorizontalAlignment=”Left” Margin=”120,91,0,0” VerticalAlignment=”Top” Content=”Hacer Click” Button.Template ControlTemplate TargetType=”Button” 5. LUZ, CÁMARA, ACCIÓN 182 RRR Si hemos trabajado en el desarrollo web, específicamente en ASP.net, notaremos que el concepto detrás de las plantillas resulta similar al de la creación de controles compuestos. Encontraremos más información en http://msdn.microsoft.com/es-es, buscando control web compuesto. SIMILITUDES 05_Silverlight.qxp 9/30/09 1:33 PM Page 182
  • 185.
    Grid Height=”38” Width=”74” BorderBackground=”#FFB0ECE8” BorderBrush=”#FF000000” BorderThickness=”2,2,2,2” CornerRadius=”5,0,5,0” TextBlock Text=”{TemplateBinding Content}” TextWrapping=”Wrap” Margin=”3,3,3,3” HorizontalAlignment=”Center” VerticalAlignment=”Center”/ /Border /Grid /ControlTemplate /Button.Template /Button En el ejemplo, la plantilla se encuentra incrustada dentro del mismo control Button, por lo que esta configuración sólo aplicará a este botón y no a otros que pudiéramos adicionar al proyecto. También es posible ver la secuencia de controles usados para de- finir el nuevo elemento. Primero el uso del control Border usado para definir el con- torno del botón y redondear dos de las esquinas del objeto. Dentro de éste, un control TextBlock utilizado para mostrar el texto del botón. Otro detalle es la aparición del va- lor {TemplateBinding Content} dentro del atributo Text del control TextBlock. Este valor asegura que el control TextBlock muestre el contenido de la misma propiedad configurada en el control padre. Como el control Button posee un atributo llamado Content, lo que se escriba en éste será transferido en forma automática al atributo Text del control TextBlock. Podemos usar este tipo de enlazados con cualquier atribu- to o propiedad presente en los elementos hijo y que pudieran ser configurados desde el elemento padre. Como habremos notado, muchos controles en Silverlight poseen efectos que se disparan cuando el usuario interactúa con ellos. Si el mouse pasa por encima del control, éste presenta una superficie de un color especial o, si es deshabili- tado, el control se muestra con otro color. Esto se debe a que, en su interior, estos con- troles manejan animaciones basadas en distintos eventos por parte del usuario, por lo que, al redefinir un control, es posible también modificar estas animaciones. Veamos un ejemplo de las animaciones declaradas para el control Button personalizado. Mover objetos 183 RRR Es importante agregar el tag vsm:VisualState x:Name=”Normal”/ cuando trabajemos con ani- maciones en las plantillas. Si hacemos esto, lograremos que, cuando el elemento modificado no esté aplicando ninguna animación, el objeto vuelva, en forma automática, a su estado original. RESTAURAR ESTADOS 05_Silverlight.qxp 9/30/09 1:33 PM Page 183
  • 186.
    Button x:Name=”Boton1” VerticalAlignment=”Top”Content=”Hacer Click” Margin=”114,40,127,0” Height=”50” Button.Template ControlTemplate TargetType=”Button” Grid Width=”{TemplateBinding Width}” Height=”{TemplateBinding Height}” vsm:VisualStateManager.VisualStateGroups vsm:VisualStateGroup x:Name=”EstadosComunes” vsm:VisualState x:Name=”Normal”/ vsm:VisualState x:Name=”MouseOver” Storyboard DoubleAnimation From=”11” To=”16” Duration=”0:0:0.2” Storyboard.TargetName=”textInterno” Storyboard.TargetProperty=”FontSize” /DoubleAnimation /Storyboard /vsm:VisualState /vsm:VisualStateGroup /vsm:VisualStateManager.VisualStateGroups Border Background=”#FFB0ECE8” BorderBrush=”#FF000000” BorderThickness=”2,2,2,2” CornerRadius=”5,0,5,0” Width=”{TemplateBinding Width}” TextBlock x:Name=”textInterno” Text=”{TemplateBinding Content}” TextWrapping=”NoWrap” Margin=”3,3,3,3” HorizontalAlignment=”Center” VerticalAlignment=”Center” FontSize=”11”/ /Border /Grid /ControlTemplate /Button.Template /Button En el código anterior, introdujimos algunos tags nuevos: • vsm:VisualStateManager: este tag representa el contenedor de los diferentes estados que puede contener el control. Dentro de éste, tenemos que agregar to- dos los estados por los cuales reaccionará el control. 5. LUZ, CÁMARA, ACCIÓN 184 05_Silverlight.qxp 9/30/09 1:33 PM Page 184
  • 187.
    • vsm:VisualStateGroup: estetag agrupa los estados en un contenedor común bajo un nombre representativo. • vsm:VisualState: representa un estado posible del control, además de contener todas las animaciones que ese estado pueda representar. Figura 20. Animaciones personalizadas en plantillas. A la izquierda, vemos el botón en su estado normal y, a la derecha, el mismo botón una vez aplicada la animación. De esta forma, las animaciones contenidas dentro del tag vsm:VisualState x:Name= ”MouseOver” se ejecutarán cuando el usuario posicione el mouse sobre el botón. La animación, en este caso, agrandará el tamaño de la fuente del texto interno del botón. Con estas características no sólo podemos modificar el control para que tenga el as- pecto que nosotros queramos, sino que, además, es posible manipular los estados por los cuales pasará nuestro control, pudiendo modificar su presentación y comporta- miento acorde a cómo el usuario interactúe con él. Mover objetos 185 … RESUMEN En este capítulo aprendimos a manipular los distintos elementos de Silverlight de forma que podamos quitarle rigidez a las aplicaciones que construyamos. Animaciones, transformacio- nes y estilos para los controles, así como algunas técnicas para presentar mejor el contenido y hacer más atractivas las interfaces con las que el usuario debe trabajar. En el próximo ca- pítulo, nos introduciremos otro poco en características visuales como las DeepZoom, y nos acercaremos más aún a los códigos C# y JavaScript. 05_Silverlight.qxp 9/30/09 1:33 PM Page 185
  • 188.
    186 PREGUNTAS TEÓRICAS 1 ¿Cuántostipos de transformaciones pode- mos encontrar en Silverlight 2? 2 Si queremos especificar una transforma- ción, ¿qué tag XAML debemos usar dentro del objeto que va a ser modificado? 3 ¿Qué parámetros son necesarios para apli- car una transformación de traslación? 4 ¿Cuál es la unidad utilizada en una trans- formación de rotación? 5 Si necesitamos rotar un objeto mediante una transformación de rotación, ¿siempre debemos realizarlo desde el centro del objeto? ¿Es posible modificar este punto de rotación? 6 ¿Cuándo debemos usar la animación lla- mada ColorAnimation? 7 ¿Cuál es el formato utilizado para especificar el tiempo de duración de las animaciones? 8 ¿Qué debemos ejecutar desde código C# para que una animación se inicie? 9 ¿Qué es un estilo en Silverlight 2? 10¿Para qué usamos plantillas en Silverlight 2? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Intente crear una animación, utilizando ColorAnimation, para modificar el color de fondo de un control en el momento en el que el ratón se posicione sobre él. 2 Busque en Internet información sobre ani- maciones cuadro a cuadro con Silverlight 2. 3 Busque animaciones xaml en http://msdn. microsoft.com/es-es para aprender más sobre transformaciones y animaciones con Silverlight 2. 4 Ingrese en http://msdn.microsoft.com/ es-es y busque animaciones 3D avanzadas para conocer más sobre simulaciones tri- dimensionales con Silverlight 2 mediante el uso de transformaciones y animaciones. 5 Ingrese en http://silverlight.net/learn/ y allí busque 78708 para ver un video sobre animaciones con Silverlight 2. 05_Silverlight.qxp 9/30/09 1:33 PM Page 186
  • 189.
    Cerrar el círculo MediaElement 188 Ejecutarsonidos 188 Video 194 Elementos con video embebido 195 Marcadores de video 196 Deep Zoom 199 Crear el primer Deep Zoom 200 Incluir Deep Zoom en Silverlight 203 Dibujar con InkPresenter 208 Dibujar en forma manual 212 Dibujar sobre otros elementos 215 InkPresenter y áreas de dibujo 217 Resumen 219 Actividades 220 Capítulo 6 Este capítulo está dedicado a tratar tres complementos de Silverlight. Y, si bien los llamaremos complementos, son tan importantes que merecen un capítulo completo. Con éstos podremos dibujar, transmitir videos y hasta manipular imágenes de alta definición de forma simple. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 06_Silverlight.qxp 9/30/09 1:33 PM Page 187
  • 190.
    MEDIAELEMENT En el capítulo2, realizamos un proyecto Silverlight que implementaba el control MediaElement para visualizar un video. Pero las características de este control pueden ir mucho más lejos y, con esto, todo lo relacionado al manejo de video dentro de Sil- verlight. Este control no tiene como único objetivo visualizar videos, ya que con él podremos también ejecutar sonidos o hacer lo que se conoce como streaming (re- producción de videos bajo demanda). Veamos, entonces, cómo extender las capaci- dades de este control maximizando las potencialidades que presenta. Ejecutar sonidos Antes de utilizar el control MediaElement para ejecutar sonidos, debemos cono- cer los formatos soportados. Si bien el control tiene pleno soporte para los for- matos creados por Microsoft, como el WMA (Windows Media Audio), también es posible consumir un formato más común como el MP3. A continuación, po- demos ver todos los formatos soportados. • WMA 7: Windows Media Audio 7. • WMA 8: Windows Media Audio 8. • WMA 9: Windows Media Audio 9. • WMA 10: Windows Media Audio 10. • MP3: ISO/MPEG Layer-3. En nuestro proyecto, si queremos reproducir música o sonido, deberemos de- clarar el control MediaElement de la siguiente forma: Grid x:Name=”LayoutRoot” Background=”White” MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3” /MediaElement /Grid 6. CERRAR EL CÍRCULO 188 RRR Para acceder a un archivo, no deberemos usar rutas que incluyan identificadores tales como C:DirectorioArchivo, sino que accederemos a los archivos como si se tratara de un recurso web, utilizando sólo rutas relativas al punto de origen de la aplicación Silverlight. RUTAS 06_Silverlight.qxp 9/30/09 1:33 PM Page 188
  • 191.
    Debemos tener sumocuidado al momento de colocar la ruta del recurso de soni- do por reproducir, ya que se requiere de una ruta relativa a la posición donde se encuentra el resultado de nuestra aplicación Silverlight. Esto quiere decir que, si el archivo de sonido se encuentra a la misma altura en el árbol de directorios que nuestra aplicación, sólo necesitaremos colocar el nombre del elemento que se re- producirá. Pero, si éste está en alguna ruta más profunda, deberemos colocar la ruta desde el punto inicial de nuestra aplicación en adelante. En el código anterior, vemos que el sonido por reproducir se encuentra dentro de la carpeta Musica a par- tir de la posición del archivo compilado, como se muestra en la siguiente figura. Figura 1. Árbol de la solución con la estructura deseada. El control MediaElement nos puede brindar información de lo que está reprodu- ciendo, así como lo que está cargando desde alguna dirección. Tengamos en cuen- ta que las pruebas que podamos hacer de forma local cargarán mucho más rápido que si consumiéramos los archivos desde Internet. Por este motivo, debido a la velocidad de carga, este control puede avisarnos el estado de ésta, así como la fi- nalización de carga del archivo en cuestión, para poder presentar información al MediaElement 189 RRR Tanto sea de video como de sonido el archivo que estamos agregando a nuestro proyecto Silverlight, debemos configurar éste para que sea copiado junto con el resultado de la aplicación cada vez que la compilemos. Podemos conseguir esta acción seleccionando el archivo y modificando la propiedad Copiar en el directorio de resultados, colocándola en Copiar siempre. ADICIÓN DE ARCHIVOS 06_Silverlight.qxp 9/30/09 1:33 PM Page 189
  • 192.
    usuario sobre estosestados. Si agregamos un control TextBlock, podremos brindar información al usuario sobre el estado de reproducción del archivo. Grid x:Name=”LayoutRoot” Background=”White” TextBlock x:Name=”Tiempo” VerticalAlignment=”Top” HorizontalAlignment=”Center”/TextBlock MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3” /MediaElement /Grid Luego, crearemos un temporizador que inspeccionará de manera continua el valor de la propiedad Position del control MediaElement, y mostrará el progreso de la re- producción del archivo en el TextBlock antes declarado. DispatcherTimer reloj; public Page() { InitializeComponent(); reloj = new DispatcherTimer(); reloj.Tick += new EventHandler(reloj_Tick); reloj.Interval = TimeSpan.FromSeconds(0.1); reloj.Start(); } void reloj_Tick(object sender, EventArgs e) { this.Tiempo.Text = “Tiempo transcurrido: “ + this.Musica.Position.TotalSeconds.ToString(); } 6. CERRAR EL CÍRCULO 190 _` En los ejemplos usamos MP3 del álbum Ghost del grupo Nine Inch Nails. Este CD es provisto por la banda de manera gratuita y es de libre uso y distribución. A pesar de esto, ha generado exce- lentes ganancias. Este álbum puede ser descargado desde la página http://ghosts.nin.com. MP3 GRATUITOS 06_Silverlight.qxp 9/30/09 1:33 PM Page 190
  • 193.
    El resultado delcódigo anterior podemos observarlo en la Figura 2, donde el conta- dor se actualiza constantemente basado en el progreso de reproducción del archivo MP3. Como vemos, el control MediaElement posee todas las características necesa- rias para administrar estos tipos de archivos. Figura 2. Aquí podemos ver la cantidad de segundos transcurridos en la reproducción del archivo.. Es posible extender un poco más nuestro ejemplo para controlar con profundidad la reproducción del archivo. Agreguemos algunos controles Slider, CheckBox y Button para manipular la reproducción del archivo MP3. Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition/ RowDefinition/ RowDefinition/ RowDefinition/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition/ /Grid.ColumnDefinitions TextBlock x:Name=”Tiempo” VerticalAlignment=”Bottom” HorizontalAlignment=”Left” Grid.Row=”1” Margin=”123,0,0,13”/ MediaElement x:Name=”Musica” Source=”Musica/Ghosts.mp3” Grid.Row=”1” AutoPlay=”False” MediaOpened=”Musica_MediaOpened” / MediaElement 191 06_Silverlight.qxp 9/30/09 1:33 PM Page 191
  • 194.
    Button HorizontalAlignment=”Left” Margin=”105,8,0,0” VerticalAlignment=”Top” Grid.Row=”2”Content=”Reproducir” d:LayoutOverrides=”Height” Click=”Button_Click”/ Button Margin=”184,8,162,0” VerticalAlignment=”Top” Grid.Row=”2” Content=”Detener” d:LayoutOverrides=”Height” Click=”Button_Click_1”/ Button HorizontalAlignment=”Right” Margin=”0,8,114,0” VerticalAlignment=”Top” Grid.Row=”2” Content=”Parar” d:LayoutOverrides=”Width, Height” Click=”Button_Click_2”/ CheckBox HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Content=”Silenciar” d:LayoutOverrides=”Height” Click=”CheckBox_Click” x:Name=”Silencio”/ Slider Margin=”105,26,114,31” Grid.Row=”1” d:LayoutOverrides=”Height” x:Name=”Progreso” ValueChanged=”Progreso_ValueChanged”/ /Grid Para cada acción o evento necesitamos crear su manejador en el código C#. Tam- bién notaremos, en el siguiente código, que hemos asignado valores al control Slider sobre la base de las características del archivo por reproducir. DispatcherTimer reloj; public Page() { InitializeComponent(); reloj = new DispatcherTimer(); reloj.Tick += new EventHandler(reloj_Tick); reloj.Interval = TimeSpan.FromSeconds(0.1); reloj.Start(); } void reloj_Tick(object sender, EventArgs e) { this.Tiempo.Text = “Tiempo transcurrido: “ + this.Musica.Position.TotalSeconds.ToString(); this.Progreso.Value = this.Musica.Position.TotalSeconds; } 6. CERRAR EL CÍRCULO 192 06_Silverlight.qxp 9/30/09 1:33 PM Page 192
  • 195.
    private void Musica_MediaOpened(objectsender, RoutedEventArgs e) { this.Progreso.Maximum = this.Musica.NaturalDuration.TimeSpan.TotalSeconds; } private void Button_Click(object sender, RoutedEventArgs e) { this.Musica.Play(); } private void Button_Click_1(object sender, RoutedEventArgs e) { this.Musica.Pause(); } private void Button_Click_2(object sender, RoutedEventArgs e) { this.Musica.Stop(); } private void Progreso_ValueChanged(object sender, RoutedPropertyChangedEventArgsdouble e) { this.Musica.Position = TimeSpan.FromSeconds(this.Progreso.Value); } private void CheckBox_Click(object sender, RoutedEventArgs e) { this.Musica.IsMuted = (bool)this.Silencio.IsChecked; } MediaElement 193 RRR Microsoft pone nuestra disposición un sitio web en el que se enseñan técnicas avanzadas en el uso del producto Microsoft Expression Blend. En este sitio, podremos aprender técnicas para optimi- zar el uso de videos, la aplicación de efectos y movimiento sobre los objetos XAML y hasta la in- terfaz de esta aplicación. En http://expression.microsoft.com buscamos Learn Expression Blend. MÁS DE MICROSOFT EXPRESSION BLEND 06_Silverlight.qxp 9/30/09 1:33 PM Page 193
  • 196.
    Figura 3. Nuestroreproductor de MP3 en el que podremos iniciar, pausar y detener la reproducción, así como saltar a cualquier posición del sonido, incluso, silenciarlo si es necesario. Video Iniciamos el capítulo con la reproducción de sonidos y música, ya que era un punto pendiente si tenemos en cuenta el ejemplo creado en el capítulo 2. A pesar de esto, el tratamiento de video con el control MediaElement tiene aún más que ofrecer. Si bien no es competencia de este libro hablar de las características del streaming de videos des- de servidores web, sí veremos cómo Silverlight nos brinda soporte para esto mediante el control MediaElement, pudiendo aplicar el video sobre superficies, leer y reconocer la información contenida en él, entre otras características. En la actualidad, el control MediaElement soporta la reproducción de los siguientes formatos de video: • WMV1: Windows Media Video 7. • WMV2: Windows Media Video 8. • WMV3: Windows Media Video 9. • WMVA: Windows Media Video Advanced Profile, non-VC-1. • WMVC1: Windows Media Video Advanced Profile, VC-1. Como podemos notar, los formatos de video son los provistos por Microsoft y se centran en el WMV (Windows Media Video). Por este motivo, es necesario con- tar con algún convertidor de video a la hora de querer reproducir video con Sil- verlight. Encontraremos variadas herramientas útiles para esto, como Windows Movie Maker incluida en la mayoría de las versiones de Windows, o, dentro del conjunto de herramientas Expression, Microsoft Expression Encoder 2. 6. CERRAR EL CÍRCULO 194 06_Silverlight.qxp 9/30/09 1:33 PM Page 194
  • 197.
    Elementos con videoembebido Ya sabemos que XAML se basa en XML para representar los distintos elementos y, por tal motivo, así como es posible en XML anidar elementos, también es posible hacerlo con XAML. En el caso del video, podemos extender las funcionalidades de vi- sualización mucho más allá de la simple representación de una película en un rectán- gulo: es posible reproducir video dentro de otros elementos, los que actuarán como una máscara. Así, si tenemos texto con un video dentro de éste, el video será visible por sobre el texto, mostrando sólo las partes que comprendan la frase o palabras de dicho elemento. Esta característica la conseguimos mediante el uso del elemen- to VideoBrush, y podemos implementarlo como sigue. MediaElement x:Name=”Video” Source=”SilverLightConMarcadores.wmv” Width=”100” Height=”50” HorizontalAlignment=”Left” Margin=”7.915,8,0,0” VerticalAlignment=”Top”/ TextBlock HorizontalAlignment=”Left” Margin=”8.085,72,0,0” VerticalAlignment=”Top” Width=”340.711” FontSize=”48” Text=”Video en texto con SilverLight” TextWrapping=”Wrap” FontWeight=”Bold” FontFamily=”Comic Sans MS” TextBlock.Foreground VideoBrush SourceName=”Video”/VideoBrush /TextBlock.Foreground /TextBlock En el código anterior, creamos un elemento MediaElement para reproducir un video. Esto es necesario para poder utilizar el tag VideoBrush, ya que éste necesita de un componente con la capacidad de reproducción de video para visualizar ese video. Pensemos en VideoBrush como la posibilidad de pintar en cualquier superficie lo que el control MediaElement está reproduciendo en este momento. En este caso, el video se pintará sobre el color de fondo del control TextBlock. Pero no sólo es po- sible aplicarlo sobre este control ya que, como dijimos, VideoBrush es una forma de MediaElement 195 RRR Si bien la versión 2 de Silverlight puede resultar limitada en la cantidad de formatos posibles para reproducción de video, la siguiente versión de Silverlight, Silverlight 3, contará con pleno soporte para los formatos de video más conocidos, incluidos los utilizados por Adobe Flash y QuickTime. FORMATOS DE VIDEO 06_Silverlight.qxp 9/30/09 1:33 PM Page 195
  • 198.
    pintar un videosobre otros elementos, sino que podríamos aplicarlo sobre cualquier otro control que posea propiedades de pintado. Como vemos en el siguiente códi- go, pintamos el mismo video sobre la superficie de un control Button. Button HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Content=”Button” Margin=”8.085,0,0,23” Height=”52” Width=”131” Button.Background VideoBrush SourceName=”Video”/VideoBrush /Button.Background /Button Notemos que VideoBrush utiliza la propiedad SourceName para especificar el nombre del control MediaElement desde donde obtendrá la fuente de video. Esto quiere de- cir que todos los cambios que nosotros realicemos al control MediaElement también afectarán a los elementos VideoBrush que pudiéramos tener en nuestra aplicación. Figura 4. Video sobre diferentes objetos. Marcadores de video Cuando trabajamos con videos, existe la posibilidad de agregarles marcas con identificaciones especiales. Estas marcas, en ocasiones, son usadas para hacer avanzar el video hasta la marca en cuestión y darle la posibilidad al usuario de ele- gir el punto para comenzar a visualizar el video. El control MediaElement puede leer las marcas en los videos para otorgar la mis- ma posibilidad, esto es, desplazar el video hasta el punto en el que se encuentre esa marca. El primer paso para trabajar con marcadores es poder reconocerlos. 6. CERRAR EL CÍRCULO 196 06_Silverlight.qxp 9/30/09 1:33 PM Page 196
  • 199.
    El control MediaElementposee un evento que nos avisará cada vez que pase por un marcador. En el siguiente código, hacemos uso de este evento para mostrar los marcadores incluidos en el video: MediaElement Source=”SilverLightConMarcadores.wmv” Width=”300” Margin=”50,25,50,84” MarkerReached=”MediaElement_MarkerReached”/ TextBlock x:Name=”TextoMarcas” VerticalAlignment=”Bottom” Text=”” TextWrapping=”Wrap” Margin=”8,0,8,8” Height=”59”/ Cada vez que se pase por un marcador, se disparará el evento MarkerReached, escri- biendo la descripción y la posición de tiempo en la que se encuentra esta marca. private void MediaElement_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e) { this.TextoMarcas.Text = “Nombre del marcador: “ + e.Marker.Text + “, encontrado en “ + e.Marker.Time.Minutes.ToString() + “:” + e.Marker.Time.Seconds.ToString(); } En la figura que aparece a continuación, podemos ver cómo se despliega la mar- ca del video en el momento de alcanzarla. Figura 5. Marca alcanzada mientras se reproduce el video. MediaElement 197 06_Silverlight.qxp 9/30/09 1:33 PM Page 197
  • 200.
    Ya que podemosdetectar cada marca, sería sencillo reconocer todos los marcadores de un video para presentárselos al usuario y que éste pueda saltar entre ellos y así navegar con mayor facilidad dentro de la reproducción en curso. TimelineMarker miMarcador; private void MediaElement_MediaOpened(object sender, RoutedEventArgs e) { miMarcador = this.Video.Markers[0]; } private void Button_Click(object sender, RoutedEventArgs e) { this.Video.Position = miMarcador.Time; this.Video.Play(); } Vemos, en el código anterior, que en el evento MediaOpened, disparado en el momen- to en que el video es cargado totalmente, leemos los marcadores. Si bien éstos pueden ser una lista, sólo tomaremos el primero que encontramos, almacenándolo en un ob- jeto del tipo TimelineMarker. Luego, por medio del evento Click de un botón, usamos el valor de tiempo de este marcador para reposicionar la reproducción del video. Co- mo vemos a continuación, al presionar el botón, el video vuelve al punto de la marca. Figura 6. A la izquierda, el video retrocedió hasta la marca. A la derecha, el video se ejecuta de manera continua. 6. CERRAR EL CÍRCULO 198 06_Silverlight.qxp 9/30/09 1:33 PM Page 198
  • 201.
    MediaElement tiene aúnmucho más por ofrecer y, por esto, iremos develando sus características en los siguientes capítulos. De cualquier manera, en este punto nos habremos dado cuenta de que la potencia de Silverlight y el manejo de elementos multimedios no son una limitación, sino que, por el contrario, pueden darnos mu- chas ventajas en el desarrollo de aplicaciones. DEEP ZOOM El concepto de Deep Zoom es el de proveer una herramienta para manipular imágenes de gran tamaño dentro de las aplicaciones Silverlight, con el objetivo de aligerar la transmisión de ellas al cliente. Además de esto, permite agregar fun- cionalidades de acercamiento gradual o zoom. Pensemos en Deep Zoom como en una técnica que despliega imágenes para el cliente, quien puede acercarse y ob- servar los detalles de estas imágenes sobre la base de su resolución. Así, si conta- mos con imágenes de alta definición, que por lo general son de varios megabytes, transmitiremos toda la imagen con el máximo de sus detalles según la demanda de información que el cliente requiera, sin tener que mover toda la imagen hasta el cliente desde el principio, lo que significaría lentitud en la carga de la aplica- ción y un elevado consumo de recursos para la transmisión de los datos. Si bien existe en el mercado este tipo de tecnología y no podríamos decir que es nueva, Deep Zoom marca una diferencia en la forma en cómo es presentada la información. Esto se debe a que, en lugar de mostrar diferentes imágenes basadas en el grado de zoom que realicemos, Deep Zoom transmitirá la imagen actual de acuerdo con el rango de visión, con la mejor resolución posible, haciendo un ba- lance entre calidad y costo de la transmisión de información hacia el cliente. De esta forma, no veremos saltos entre cada uno de los grados de zoom y siempre ob- tendremos una imagen de alta calidad obtenida desde la imagen original. Si queremos empezar a trabajar con Deep Zoom, necesitaremos descargar la aplicación Deep Zoom Composer desde el sitio web de Microsoft. Deep Zoom Composer no tienen ningún costo asociado, por lo que podremos descargarlo y usarlo libremente. Deep Zoom 199 _` Hard Rock Cafe fue uno de los primeros sitios en utilizar la tecnología Deep Zoom. La empresa lo implementó en su web para que los usuarios pudieran ver la colección de objetos, cartas, ins- trumentos y otros elementos que poseen y que fueran entregados por diferentes artistas de la música. Podemos ver el sitio de Memorabilia en http://memorabilia.hardrock.com. UNO DE LOS PRIMEROS DEEP ZOOM 06_Silverlight.qxp 9/30/09 1:33 PM Page 199
  • 202.
    Crear el primerDeep Zoom Para crear un componente Deep Zoom, necesitamos una o varias imágenes, preferen- temente de alta definición, y haber instalado la aplicación Deep Zoom Composer. Una vez que consigamos esto, el primer paso es crear una aplicación nueva. Figura 7. Creación de un nuevo proyecto con Deep Zoom Composer. Hasta la fecha, Deep Zoom Composer sólo se encuentra disponible en idioma inglés. A pesar de esto, su uso resulta simple e intuitivo, por lo que no tendremos problemas en entender los pasos de la creación de este tipo de proyectos. Entonces, presionamos sobre la opción New Project…. Al hacerlo, veremos la ventana para la creación del nue- vo proyecto, donde introduciremos su nombre y la ruta física donde se alojará. Con el proyecto creado, necesitamos completar tres pasos antes de obtener el producto final. El primero es la importación de imágenes a partir del botón Import, ubicado en la parte superior. Podremos importar tantas como necesitemos y, si bien uno de los pa- sos es acomodar estas imágenes según cómo queramos que se visualicen, es recomen- dable, en caso de tener múltiples imágenes que juntas formen una sola, utilizar otras herramientas externas de composición de imágenes para unirlas en una, ya que Deep Zoom Composer sólo nos proveerá de elementos básicos para hacer este trabajo. Una vez adicionadas las imágenes, éstas aparecerán en la lista de la derecha. 6. CERRAR EL CÍRCULO 200 RRR Tenemos la posibilidad de descargar DeepZoom Composer desde el sitio de descargas de Mi- crosoft (www.microsoft.com/downloads). Allí, podremos acceder a la descarga realizando una búsqueda con el nombre de la aplicación dentro del sitio web de Microsoft. DEEP ZOOM COMPOSER 06_Silverlight.qxp 9/30/09 1:33 PM Page 200
  • 203.
    Figura 8. Eneste caso, adicionamos una imagen al proyecto. El siguiente paso de nuestro trabajo consiste en la composición de las imágenes y cómo estarán distribuidas en las aplicación Deep Zoom. Presionando en el bo- tón Compose, ubicado en la parte superior de Deep Zoom Composer, accedere- mos al siguiente paso. Arrastrando las imágenes al lienzo de trabajo, colocaremos cada una de ellas en la posición en la que queremos que se visualicen, como se muestra en la figura que aparece a continuación. Figura 9. Una imagen ubicada en el centro de Deep Zoom. Deep Zoom 201 06_Silverlight.qxp 9/30/09 1:34 PM Page 201
  • 204.
    El último pasoconsiste en generar el proyecto exportándolo al formato que pueda en- tender Silverlight. Para esto, presionamos sobre la última opción de las tres superio- res, llamada Export. Al hacer esto, tendremos que elegir el formato de exportación del proyecto. Si necesitamos ver un ejemplo completo de la implementación de Deep Zoom basado en nuestro proyecto, podremos elegir la opción Silverlight Deep Zoom. Ésta creará un proyecto completo Silverlight que incluya botones para realizar zooms y movimientos sobre las imágenes incluidas en él. Si, por el contrario, tenemos cierta experiencia en la inclusión del resultado de Deep Zoom Composer en aplicaciones Silverlight, elegiremos la opción Images para que la aplicación cree sólo los archivos necesarios para que incluyamos, por nuestra cuenta, el proyecto Deep Zoom en nues- tra aplicación Silverlight. También es posible elegir la calidad de la representación de las imágenes que se van a mostrar. En la Figura 10, en la parte inferior derecha, vemos las opciones de compresión de imagen. Esta compresión modifica el resultado de las imágenes del archivo Deep Zoom resultante. Modificar estos valores podría acelerar el proceso de descarga de las imágenes hacia el cliente, pero al mismo tiempo, un al- to nivel de compresión podría deteriorar la calidad de las imágenes. Figura 10. Vista final de Deep Zoom Composer para la exportación del proyecto. Una vez que el proyecto fue generado y, dependiendo de las opciones que hubiéra- mos elegido para generarlo, se nos presentará la opción de acceder al resultado. Es- ta opción nos llevará a la carpeta con los resultados del proyecto. El proyecto en sí es representado por un conjunto de archivos entre los que se encuentran los dife- rentes muestreos de imágenes relacionados con las imágenes utilizadas para crear el proyecto Deep Zoom, además de archivos XML con meta datos. 6. CERRAR EL CÍRCULO 202 06_Silverlight.qxp 9/30/09 1:34 PM Page 202
  • 205.
    Figura 11. Resultadodel proyecto Deep Zoom. Incluir Deep Zoom en Silverlight Para incrustar el resultado del proyecto Deep Zoom en Silverlight, crearemos un nuevo proyecto Silverlight seleccionando la opción para que Visual Studio 2008 cree un sitio web adicional para ejecutar el proyecto (podemos recurrir al capítulo 3 para recordar este paso). Una vez creado, deberemos ver el árbol de la solución. Figura 12. Proyecto Silverlight junto a un proyecto web para depuración. Notaremos que el proyecto web contiene una carpeta llamada ClientBin. Esta car- peta es la contenedora de los resultados que obtenemos luego de la compilación Deep Zoom 203 06_Silverlight.qxp 9/30/09 1:34 PM Page 203
  • 206.
    de la aplicaciónSilverlight y es el lugar donde se ubicará físicamente nuestra apli- cación. Por eso, para tener acceso al contenido del proyecto Deep Zoom, allí ten- dremos que colocar todos los archivos resultantes de Deep Zoom. Podemos ver un ejemplo de esta acción en la siguiente figura. Figura 13. En el árbol de soluciones, vemos los archivos del proyecto Deep Zoom. Una vez que tenemos los archivos en su lugar, usaremos el control MultiScaleImage para desplegarlas en el proyecto. Podemos ver un ejemplo a continuación. UserControl x:Class=”Capitulo6MiDeepZoom.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” MultiScaleImage x:Name=”MiDeepZoom” Width=”350” Height=”250” Source=”mideepzoom/dzc_output.xml”/MultiScaleImage /Grid /UserControl Observemos que el motivo por el que colocamos el proyecto Deep Zoom dentro de la misma carpeta donde se despliega el resultado de la aplicación Silverlight es para que resulte más simple poder accederla. También es importante el archivo al cual se hace referencia, que es dzc_output.xml, archivo que contiene los metadatos del proyecto, como lista de imágenes y direcciones, entre otros. 6. CERRAR EL CÍRCULO 204 06_Silverlight.qxp 9/30/09 1:34 PM Page 204
  • 207.
    El paso quehicimos sólo mostrará el proyecto si desplegamos el estado inicial que hu- biéramos configurado en el momento de crear el proyecto en Deep Zoom Composer. Necesitaremos hacer algo de código para crear la interacción con las imágenes y que el comportamiento de Deep Zoom se haga presente. Primero, modificaremos un poco el código XAML para incluir llamadas a los eventos que se relacionan con el mouse. Grid x:Name=”LayoutRoot” Background=”White” MouseMove=”LayoutRoot_MouseMove” MouseLeftButtonDown=”LayoutRoot_MouseLeftButtonDown” MouseLeftButtonUp=”LayoutRoot_MouseLeftButtonUp” MultiScaleImage x:Name=”MiDeepZoom” Width=”350” Height=”250” Source=”mideepzoom/dzc_output.xml” MouseLeave=”MiDeepZoom_MouseLeave”/MultiScaleImage /Grid Estos eventos se dispararán cuando el botón izquierdo del ratón sea presionado, cuando se mueva e, incluso, cuando deje la zona en la que se está presentando el proyecto Deep Zoom. Cada uno de estos eventos tendrá el código asociado co- mo podemos ver a continuación: private bool RatonPresionado; private bool RatonArrastrando; private Point UltimaPosicionRaton; private Point DesfaseArrastre; private Point PosicionActual; private double FactorZoom; private void MiDeepZoom_MouseLeave(object sender, MouseEventArgs e) { RatonArrastrando = false; } private void LayoutRoot_MouseMove(object sender, MouseEventArgs e) { if (RatonPresionado) { RatonArrastrando = true; } this.UltimaPosicionRaton = e.GetPosition(this.MiDeepZoom); Deep Zoom 205 06_Silverlight.qxp 9/30/09 1:34 PM Page 205
  • 208.
    if (RatonArrastrando) { Point newOrigin= new Point(); newOrigin.X = PosicionActual.X - (((e.GetPosition(MiDeepZoom).X - DesfaseArrastre.X) / MiDeepZoom.ActualWidth) * MiDeepZoom.ViewportWidth); newOrigin.Y = PosicionActual.Y - (((e.GetPosition(MiDeepZoom).Y - DesfaseArrastre.Y) / MiDeepZoom.ActualHeight) * MiDeepZoom.ViewportWidth); MiDeepZoom.ViewportOrigin = newOrigin; } } private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { RatonPresionado = true; RatonArrastrando = false; DesfaseArrastre = e.GetPosition(this); PosicionActual = MiDeepZoom.ViewportOrigin; } private void LayoutRoot_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { RatonPresionado = false; if (RatonArrastrando == false) { bool shiftApretado = (Keyboard.Modifiers ModifierKeys.Shift) == ModifierKeys.Shift; FactorZoom = 2.0; 6. CERRAR EL CÍRCULO 206 RRR Si necesitamos saber cómo manejar la rueda del mouse para realizar zoom, podemos generar un proyecto Deep Zoom con Deep Zoom Composer, que también genere un proyecto Silverlight para incluir el resultado de Deep Zoom. El código generado por Deep Zoom Composer nos otor- gará excelente código de ejemplo para nuestras implementaciones. MANEJO DE LA RUEDA DEL MOUSE 06_Silverlight.qxp 9/30/09 1:34 PM Page 206
  • 209.
    if (shiftApretado) FactorZoom= 0.5; Zoom(FactorZoom, this.UltimaPosicionRaton); } RatonArrastrando = false; } public void Zoom(double zoom, Point pointToZoom) { Point puntoLogico = this.MiDeepZoom.ElementToLogicalPoint(pointToZoom); this.MiDeepZoom.ZoomAboutLogicalPoint(zoom, puntoLogico.X, puntoLogico.Y); } El código anterior puede resultar confuso a primera vista, pero todo se reduce al método ZoomAboutLogicalPoint provisto por el control MultiScaleImage. Este mé- todo es el encargado de generar el efecto de zoom basado en un factor de zoom, tanto positivo como negativo, así como sobre la base de un punto XY. Este mé- todo se ejecuta en el método Zoom del código anterior, ya que las demás líneas de código se encargan de administrar el estado del mouse antes de realizar algu- na acción. Si ejecutamos el proyecto, veremos que al presionar sobre la imagen se realizará el acercamiento a ella, mientras que si lo hacemos presionando la te- cla SHIFT (mayúsculas) al mismo tiempo que pulsamos el botón del mouse, la imagen se alejará. A continuación, un ejemplo. Figura 14. Observamos, en cada navegador, el resultado de interactuar con la aplicación Deep Zoom. Deep Zoom 207 06_Silverlight.qxp 9/30/09 1:34 PM Page 207
  • 210.
    DIBUJAR CON INKPRESENTER Silverlighttrae consigo otros complementos, en especial, interesantes. Uno de estos es InkPresenter, un componente que facilita la escritura manual sobre cualquier aplicación Silverlight. Si bien el modelo de escritura a mano puede estar ligado con los dispositivos móviles inteligentes como Pocket PCs o Tablet PCs, Silverlight incorpora esta capacidad también, pudiendo enriquecer aún más el conjunto de fun- cionalidades ofrecidas hasta el momento. Existen casos dentro del desarrollo de apli- caciones empresariales donde puede ser necesario el reconocimiento de firmas electrónicas, que son almacenadas en bases de datos y comparadas luego para su va- lidación. También podría ser interesante brindarle al usuario la posibilidad de enviar tarjetas electrónicas escritas por él, dejando de lado el texto plano automati- zado que, por lo común, suele emplearse para este tipo de aplicaciones. Entonces, InkPresenter es un control en Silverlight que nos otorgará una superfi- cie de dibujado a mano haciendo uso del mouse, donde podremos capturar lo es- crito, almacenarlo y procesarlo para su posterior uso. Además, InkPresenter viene acompañado de un conjunto de APIs (Application Programming Interfaces o en cas- tellano, interfaz para programación de aplicaciones) para el reconocimiento de los patrones introducidos por el usuario y su transformación en texto plano legible. Veamos la declaración de un elemento InkPresenter desde código XAML. InkPresenter/InkPresenter El tag XAML del control InkPresenter agregará el lienzo de dibujo a nuestra apli- cación, y sólo podremos dibujar sobre él. Por este motivo, el control InkPresenter deberá estar declarado por encima de cualquier otro elemento. Si algún otro com- ponente se dibujara sobre el control InkPresenter, no podríamos visualizarlo y tam- poco escribir sobre él, ya que los eventos relacionados con la captura de información no serían alcanzados. Para entender esto, pensemos en capas u hojas de dibujo. La capa superior y visible, la más cercana al usuario, es la que puede interactuar con él, capturando cualquier tipo de acción que el usuario realice, dejando a las capas 6. CERRAR EL CÍRCULO 208 RRR Los tipos de datos para colores en XAML son representados en formato hexadecimal, de ma- nera similar al utilizado en HTML, con la diferencia de que, en Silverlight, se incluye un par de números iniciales para especificar el nivel de transparencia de ese color. Si contamos con #FF000000, obtenemos un color negro pleno y sin transparencias. COLORES 06_Silverlight.qxp 9/30/09 1:34 PM Page 208
  • 211.
    inferiores fuera delalcance de estos eventos. Por eso, deberemos asegurarnos de que el control InkPresenter se posicione sobre la capa superior y más cercana al usuario. Veamos, ahora, la declaración completa del control InkPresenter. Grid x:Name=”LayoutRoot” Background=”White” InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4” Margin=”8,8,8,8” Opacity=”1” MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown” MouseMove=”inkPresenter_MouseMove” LostMouseCapture=”inkPresenter_LostMouseCapture”/ /Grid Figura 15. Podemos ver el lienzo de InkPresenter incorporado en nuestro proyecto. Del código anterior, los atributos destacables son los tres eventos relacionados con la acción de escritura. A continuación, veamos sus detalles: • MouseLeftButtonDown: este evento se refiere al momento en el que el usuario pre- siona el botón izquierdo del mouse. En este evento, inicializaremos la captura de información del control InkPresenter. • MouseMove: cada vez que el usuario mueva el mouse sobre el lienzo de InkPresenter, este evento se disparará. Al dispararse, guardaremos la información capturada pa- ra que sea mostrada en el lienzo. • LostMouseCapture: en el momento en que el botón del mouse sea liberado o el con- trol deje de percibir información desde el usuario, este evento será disparado. Dibujar con InkPresenter 209 06_Silverlight.qxp 9/30/09 1:34 PM Page 209
  • 212.
    Figura 16. Aquí,podemos ver el control InkPresenter en acción. Antes de comenzar a crear código para poder dibujar sobre InkPresenter, es ne- cesario configurar los límites de dibujo ya que, si bien el control representa un elemento rectangular, podemos especificar los espacios donde se podrá escribir o no. Esto puede resultar muy versátil cuando necesitamos adaptar las caracterís- ticas de dibujo a una zona en particular. public Page() { InitializeComponent(); Limites(); } private void Limites() { RectangleGeometry Rectangulo = new RectangleGeometry(); Rectangulo.Rect = new Rect(0, 0, this.inkPresenter.Width, this.inkPresenter.Height); this.inkPresenter.Clip = Rectangulo; } Los límites elegidos en este caso son representados por un rectángulo con el mis- mo tamaño que el control InkPresenter. Esto hará que podamos escribir sobre toda la superficie del control libremente. El siguiente paso es escribir el código detrás de cada uno de los eventos antes mencionados. 6. CERRAR EL CÍRCULO 210 06_Silverlight.qxp 9/30/09 1:34 PM Page 210
  • 213.
    private Stroke pincel; privatevoid inkPresenter_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { this.inkPresenter.CaptureMouse(); StylusPointCollection ColeccionDeEstilos = new StylusPointCollection(); ColeccionDeEstilos.Add(e.StylusDevice.GetStylusPoints(this.inkPresenter)); pincel = new Stroke(ColeccionDeEstilos); this.inkPresenter.Strokes.Add(pincel); } Dentro del código anterior, en el evento MouseLeftButtonDown, iniciamos la cap- tura del mouse, además de configurar el tipo de pincel que se va a utilizar para realizar el dibujo. Por defecto, este pincel será básico y de color negro. Por su parte, el segundo evento se encargará de analizar las coordenadas del mouse a medida que éste se desplaza por el control. private void inkPresenter_MouseMove(object sender, MouseEventArgs e) { if (pincel != null) pincel.StylusPoints.Add(e.StylusDevice.GetStylusPoints(this.inkPresenter)); } Como vemos en este código, es necesario verificar que el pincel haya sido crea- do antes de capturar los trazos generados por el mouse. Si no hiciéramos esto, el usuario, al mover el mouse, crearía trazos continuos. Por último, incorporamos el código relacionado al último evento. private void inkPresenter_LostMouseCapture(object sender, MouseEventArgs e) { pincel = null; } Una vez que el botón del mouse es liberado, el pincel se elimina, haciendo que ya no se dibujen los movimientos del usuario sobre el control. Dibujar con InkPresenter 211 06_Silverlight.qxp 9/30/09 1:34 PM Page 211
  • 214.
    Dibujar en formamanual Como ya dijimos, InkPresenter representa trazos creados por el usuario. Estos trazos no sólo pueden ser introducidos por el usuario, sino que es posible que nosotros proveamos estos elementos desde el comienzo. La realización de este trabajo nos lleva a la posibilidad de guardar información de trazos generados por el usuario y, luego, mostrarlos sin intervención de su parte. Figura 17. Trazos creados con XAML. Como vemos en la figura anterior, el control InkPresenter puede mostrar trazos ba- sados en tags creados de manera manual. Veamos, a continuación, el código XAML: ... ... InkPresenter.Strokes StrokeCollection Stroke Stroke.DrawingAttributes DrawingAttributes Color=”#FF000000” Width=”5” Height=”5” / /Stroke.DrawingAttributes Stroke.StylusPoints StylusPoint X=”10” Y=”10” / StylusPoint X=”100” Y=”10” / 6. CERRAR EL CÍRCULO 212 06_Silverlight.qxp 9/30/09 1:34 PM Page 212
  • 215.
    StylusPoint X=”100” Y=”100”/ StylusPoint X=”10” Y=”100” / StylusPoint X=”10” Y=”10” / /Stroke.StylusPoints /Stroke /StrokeCollection /InkPresenter.Strokes /InkPresenter Cada tag Stroke dentro del tag StrokeCollection representa un trazo único. Esto es el equivalente a que el usuario hubiera creado dicho trazo sin dejar de presionar el botón del mouse. El tag Stroke.DrawingAttributes representa la característica del trazado. En el ejemplo, éste muestra un grosor de 5 pixeles de ancho y 5 pixeles de alto, además de ser de color negro. Por último, encontramos cada uno de los puntos del trazo representados por la colección Stroke.StylusPoints, que contendrá cada uno de los puntos basados en el tag StylusPoint, el cual especifica las coordenadas XY donde se inicia el punto. Debido a que éste es un único trazo, al dibujar más puntos en diferentes coordenadas, éstos se uniránmediante una línea. Como vemos en la Figura 17, la unión de los puntos derivó en la construcción de un cuadrado. Y así como creamos trazos desde el código XAML, también podemos hacerlo desde nuestro código, como observamos en la Figura 18. Allí, la línea de color verde es cre- ada desde el código XAML. Esto se logra siguiendo el mismo patrón que el de XAML. El siguiente código muestra cómo generar estos trazos desde código C#. Figura 18. Trazos creados por código. Dibujar con InkPresenter 213 06_Silverlight.qxp 9/30/09 1:34 PM Page 213
  • 216.
    private void Button_Click(objectsender, RoutedEventArgs e) { Stroke trazo = new Stroke(); trazo.DrawingAttributes.Width = 3; trazo.DrawingAttributes.Height = 3; trazo.DrawingAttributes.Color = Color.FromArgb(150, 50, 150, 150); StylusPointCollection coleccionEstilos = new StylusPointCollection(); StylusPoint punto = new StylusPoint(); punto.X = 150; punto.Y = 10; coleccionEstilos.Add(punto); StylusPoint punto2 = new StylusPoint(); punto2.X = 300; punto2.Y = 10; coleccionEstilos.Add(punto2); StylusPoint punto3 = new StylusPoint(); punto3.X = 300; punto3.Y = 100; coleccionEstilos.Add(punto3); trazo.StylusPoints.Add(coleccionEstilos); this.inkPresenter.Strokes.Add(trazo); } Si comparamos el patrón XAML con el código antes presentado, notaremos sus similitudes. Primero se crea el trazo, especificando el color y el grosor que tendrá. Stroke trazo = new Stroke(); trazo.DrawingAttributes.Width = 3; trazo.DrawingAttributes.Height = 3; trazo.DrawingAttributes.Color = Color.FromArgb(150, 50, 150, 150); ... ... Luego, creamos el contenedor de la colección de puntos por dibujar y adiciona- mos cada uno de los puntos, como vemos en el siguiente código: 6. CERRAR EL CÍRCULO 214 06_Silverlight.qxp 9/30/09 1:34 PM Page 214
  • 217.
    ... StylusPointCollection coleccionEstilos =new StylusPointCollection(); StylusPoint punto = new StylusPoint(); punto.X = 150; punto.Y = 10; coleccionEstilos.Add(punto); ... Dibujar sobre otros elementos Si seguimos el mismo modelo de dibujo sobre el elemento InkPresenter, veremos que es posible extenderlo para que podamos dibujar sobre cualquier otro control que deseemos. Esto resulta especialmente útil sobre controles y componentes con capacidades de desplegar imágenes y videos. Figura 19. Es posible dibujar sobre una imagen preestablecida. El control InkPresenter puede contener otros controles, por lo que, para lograr lo visto en la figura anterior, tendremos que agregar el control Image como con- tenido del control InkPresenter. Veamos cómo hacerlo: InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4” Margin=”8,8,8,8” Opacity=”1” Width=”384” Height=”284” Dibujar con InkPresenter 215 06_Silverlight.qxp 9/30/09 1:34 PM Page 215
  • 218.
    MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown” MouseMove=”inkPresenter_MouseMove” LostMouseCapture=”inkPresenter_LostMouseCapture” Image Source=”Colinas azules.jpg”Width=”384” Height=”284”/ /InkPresenter Luego, podremos intercambiar este elemento interno por cualquier otro capaz de representar algún medio visual. El código para escribir sobre video resultará similar al anterior. En este caso, utilizamos un control MediaElement para des- plegar el video y escribir sobre él. En la Figura 20 que encontramos debajo pode- mos ver un ejemplo del resultado que se podría obtener. InkPresenter x:Name=”inkPresenter” Background=”#FFCBD8E4” Margin=”8,8,8,8” Opacity=”1” Width=”384” Height=”284” MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown” MouseMove=”inkPresenter_MouseMove” LostMouseCapture=”inkPresenter_LostMouseCapture” MediaElement Source=”silverlight.wmv” AutoPlay=”True” / /InkPresenter Figura 20. En este caso, utilizamos el mismo concepto para escribir sobre video. 6. CERRAR EL CÍRCULO 216 06_Silverlight.qxp 9/30/09 1:34 PM Page 216
  • 219.
    InkPresenter y áreasde dibujo Si bien el control InkPresenter se muestra, por lo general, como un rectángulo, re- sulta lo bastante versátil como para poder definir áreas permitidas para dibujar so- bre él. En este caso, el control InkPresenter aparecerá con bordes redondeados, y los trazos realizados por el usuario no podrán sobrepasar estos límites. Para conseguir esto, podemos hacer uso de la propiedad Clip del control. Lo haremos de la misma forma que hemos empleado para asignar un área rectangular, pero, en este caso, es- pecificaremos una matriz de puntos que representen las esquinas curvas. InkPresenter x:Name=”inkPresenter” Width=”300” Height=”200” Background=”Aqua” MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown” MouseMove=”inkPresenter_MouseMove” LostMouseCapture=”inkPresenter_LostMouseCapture” Clip=”M0.5,25.5 C0.5,11.692881 11.692881,0.5 25.5,0.5 L267,0.5 C280.80713,0.5 299,19.192881 299,33 L299,169 C299,182.80713 289.80713,201 276,201 L29,201 C15.192881,201 0.5,186.80713 0.5,173 z” / Figura 21. Aquí podemos ver cómo, al intentar dibujar por sobre las esquinas curvas, la línea de dibujo no es representada. Si bien los valores introducidos en la propiedad Clip pueden resultar complejos de en- tender y de crear en forma manual, Expression Blend 2 nos otorga herramientas para hacerlo de manera visual y más simple. Allí, creamos el contorno que vamos a aplicar, y luego copiamos y pegamos el resultado en el control InkPresenter. Primero debere- mos agregar un elemento de dibujo al lienzo. Podremos usar elipses o rectángulos. Una Dibujar con InkPresenter 217 06_Silverlight.qxp 9/30/09 1:34 PM Page 217
  • 220.
    vez agregado elelemento, deberemos transformarlo a un tipo de elemento de traza- do. Para conseguir esto, presionamos el botón izquierdo del mouse sobre el elemento de dibujo, para seleccionar la opción Convertir en trazado dentro de Trazado. Figura 22. Convirtiendo la elipse a un trazado. Luego de convertir el elemento a trazado, es posible deformarlo a gusto para conseguir la forma que queramos. Por último, aplicaremos este trazado al control InkPresenter. Figura 23. El trazado completamente modificado. Para aplicar el trazado, copiaremos el valor del atributo Data del trazado al atributo Clip de InkPresenter. Como resultado, en este caso obtendremos el siguiente código: 6. CERRAR EL CÍRCULO 218 06_Silverlight.qxp 9/30/09 1:34 PM Page 218
  • 221.
    InkPresenter x:Name=”inkPresenter” Width=”300” Height=”250”Background=”Aqua” MouseLeftButtonDown=”inkPresenter_MouseLeftButtonDown” MouseMove=”inkPresenter_MouseMove” LostMouseCapture=”inkPresenter_LostMouseCapture” Clip=”M289.97556,99.001045 C255.73196,134.51219 198.63127,225.33125 119.70698,220.46407 C73.678635,217.62555 -25.515903,142.05704 16.996023,143.14827 C35.799923,143.63094 25.502108,94.232025 33.899151,74.349686 C49.08622,38.390076 115.76089,-10.094691 156.73918,49.198044 C206.78326,121.60835 319.49466,68.389313 289.97556,99.001045 z” / Figura 24. El trazo de dibujo sólo se aplicará a las zonas preestablecidas en la propiedad Clip. Dibujar con InkPresenter 219 … RESUMEN Videos, imágenes escalables y capacidades de dibujo; herramientas de Silverlight que pueden enriquecer nuestras aplicaciones de una forma inmensurable. Si los controles y componentes, junto a sus capacidades vistas en capítulos anteriores, no nos habían despertado aún la imagi- nación, poder manipular imágenes de alta resolución o escribir sobre cualquier superficie es lo que faltaba para romper la barrera de lo tradicional y forzarnos a crear aplicaciones que pre- senten el contenido de formas antes impensadas. 06_Silverlight.qxp 9/30/09 1:34 PM Page 219
  • 222.
    220 PREGUNTAS TEÓRICAS 1 ¿QuéformatosdeaudiosoportaSilverlight2? 2¿Mediante qué métodos podemos saber la posición actual de reproducción de un soni- do o música? 3 ¿Qué método es necesario ejecutar para quitar el sonido por completo de una re- producción en curso? 4 ¿Qué control necesitamos para reproducir video en las aplicaciones Silverlight 2? 5 ¿Cuáles son los formatos de video que pue- den ser manejados por Silverlight 2? 6 ¿A qué hace referencia la tecnología Deep Zoom? 7 ¿Qué control XAML necesitamos utilizar pa- ra incluir un elemento Deep Zoom dentro de nuestra aplicación Silverlight 2? 8 ¿Cuál es el objetivo del archivo denominado dzc_output.xml? 9 ¿Cómo se reconocen los trazos creados con InkPresenter desde el código C#? 10¿Qué objeto define el tipo de trazo usado por InkPresenter? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Intente reproducir sonidos desde una di- rección web remota, haciendo uso del con- trol MediaElement. 2 InkPresenter para Windows Presentation Foundation posee la capacidad de recono- cer la escritura y transformarla a letras. Intente implementar esta característica. 3 Recolecte la información creada con Ink- Presenter y almacénela en formato XML. 4 Con la información recolectada en el ejer- cicio anterior, trate de volver a mostrarla en la aplicación Silverlight 2. 5 Teniendo diferentes imágenes, intente crear una presentación Deep Zoom. Con la información que este componente retorna, muestre información en una aplicación Sil- verlight 2 basada en la imagen que el usua- rio esté visualizando. 06_Silverlight.qxp 9/30/09 1:34 PM Page 220
  • 223.
    Interconexión Ampliar las funcionalidades222 Silverlight desde C# 222 WebClient 230 Enviar información 233 Almacenamiento aislado 239 Implementar el almacenamiento aislado 240 Capacidad de almacenamiento 245 Almacenar configuraciones 247 OpenFileDialog 251 Manejo de hilos 255 El concepto de hilos 256 Temporizador 257 Personalizar los hilos 259 Hilos y eventos 261 Consumir servicios desde Silverlight 263 Crear un servicio WCF 270 Manipular datos 275 Enlazado de datos 276 LinQ 283 Resumen 287 Actividades 288 Capítulo 7 En el ambiente de Internet, aquello que extiende las capacidades de las aplicaciones es la facilidad con la que se puede consumir información de distintos medios, incluso fuera de nuestro dominio. Consultar la cotización de una moneda o el clima son sólo una parte del todo que puede ser construido, y Silverlight no queda exento. Veamos el porqué. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 07_Silverlight.qxp 9/30/09 1:35 PM Page 221
  • 224.
    AMPLIAR LAS FUNCIONALIDADES Sibien en los capítulos vistos hasta ahora hemos hecho uso de C# para potenciar al- gunas de las funcionalidades de Silverlight, debemos reconocer que la mayoría del tra- bajo realizado recayó sobre el código XAML. Esto se debe a que mucha funcionalidad puede ser creada desde el mismo código XAML, colocando sólo algunas gotas de C# como soporte. De cualquier manera, lo que podríamos conseguir redunda en los as- pectos visuales y no genera mayor interacción con el usuario que haga uso de nuestra aplicación Silverlight. Sin embargo, con líneas de código de programación avanzadas, en Silverlight podemos hacer mucho más, como conectarnos a servicios web para consumir o enviar información, modificar la estructura del código XAML en tiempo de ejecución o almacenar información en el equipo del usuario para utilizarla con pos- terioridad. En este capítulo hablaremos de estas cualidades por medio de ejemplos va- riados, donde extenderemos la aplicación Silverlight para que pase de ser un simple visualizador de imágenes y videos, o un contenedor de animaciones, a algo mucho más robusto y listo para ser usado en ámbitos empresariales o con fines tales como el comercio electrónico o, por qué no, hasta la creación de juegos en la red. SILVERLIGHT DESDE C# Es posible que una de las áreas más atractivas del desarrollo de software sea la que se refiere a la creación de juegos. En ésta se suelen aplicar muchas ciencias y técnicas externas del software, como el uso de la física o la matemática. Al mismo tiempo, en este tipo de desarrollo nos encontramos con acertijos lógicos que desafían nuestro intelecto al tratar de optimizar al máximo el uso de recursos del equipo o para en- contrar la mejor forma posible de mover elementos por la pantalla y simular anima- ciones típicamente relacionadas con los juegos. Iniciemos, entonces, el uso intensivo de C# para Silverlight con la creación de un juego. Este juego es bastante conocido y consiste en armar una imagen desplazando cuadrados, que contienen parte de ella, a un único espacio vacío del tablero de juego. Podremos mover sólo una parte a la vez, tratando de formar la imagen previsualizada de manera completa. Primero, crearemos en el código XAML una superficie de dibujado; para esto, necesitaremos de un con- trol Canvas y un control Image donde visualizar la figura correctamente ensamblada. UserControl x:Class=”Capitulo7ModificacionCanvas.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”810” Height=”300” 7. INTERCONEXIÓN 222 07_Silverlight.qxp 9/30/09 1:35 PM Page 222
  • 225.
    xmlns:d=”http://schemas.microsoft.com/expression/blend/2008” xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006” mc:Ignorable=”d” Grid x:Name=”LayoutRoot” Background=”White” Canvasx:Name=”ContenedorJuego” / Image Source=”Froblins4.png” Height=”300” Width=”400” Stretch=”Fill” HorizontalAlignment=”Right” d:LayoutOverrides=”HorizontalAlignment, Width”/ TextBlock Visibility=”Collapsed” HorizontalAlignment=”Left” VerticalAlignment=”Top” Text=”¡Has Ganado!” TextWrapping=”Wrap” Margin=”109,132,0,0” FontSize=”20” Width=”144.658” FontWeight=”Bold” FontFamily=”Interfaz de usuario portátil” x:Name=”textblockGanador”/ /Grid /UserControl En la Figura 1, vemos cómo se muestra la imagen y, también, podemos visualizar el árbol de soluciones, donde notaremos que hemos agregado una imagen a él. Esta imagen será usada como modelo guía, tanto para que el jugador pueda saber cuál es el resultado final por ensamblar, como para que nuestro código tome esta ima- gen y la desordene en pequeñas piezas para crear la esencia del juego. Figura 1. Primera figura definida en el control Image. El segundo paso consta de la creación del tablero de juego. Para esto, crearemos código que cargue la imagen de manera dinámica desde una dirección web dada. Silverlight desde C# 223 07_Silverlight.qxp 9/30/09 1:35 PM Page 223
  • 226.
    public Page() { InitializeComponent(); CrearTablero(); } Canvas[] vectorCanvas= new Canvas[16]; Image[] imagenes = new Image[16]; int[] tablero = new int[16]; private void CrearTablero() { Uri uri = new Uri(“Froblins4.png”, UriKind.Relative); int n = 0; for (int x = 0; x 4; x++) for (int y = 0; y 4; y++) { n = (x * 4) + y; imagenes[n] = new Image(); imagenes[n].Height = 400; imagenes[n].Width = 400; imagenes[n].Stretch = Stretch.UniformToFill; RectangleGeometry r = new RectangleGeometry(); r.Rect = new Rect((x * 100), (y * 100), 100, 100); imagenes[n].Clip = r; imagenes[n].Source = new BitmapImage(uri); imagenes[n].SetValue(Canvas.TopProperty, Convert.ToDouble(y * 100 * -1)); imagenes[n].SetValue(Canvas.LeftProperty, Convert.ToDouble(x * 100 * -1)); vectorCanvas[n] = new Canvas(); vectorCanvas[n].Width = 100; vectorCanvas[n].Height = 100; vectorCanvas[n].Children.Add(imagenes[n]); vectorCanvas[n].SetValue(Canvas.NameProperty, “C” + n.ToString()); vectorCanvas[n].MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown); if (n 15) 7. INTERCONEXIÓN 224 07_Silverlight.qxp 9/30/09 1:35 PM Page 224
  • 227.
    this.ContenedorJuego.Children.Add(vectorCanvas[n]); } barajar(); dibujarTablero(); } Notemos que, pormedio del objeto Uri, hacemos referencia a la imagen que se va a cargar, imagen que será usada para definir el tablero de juego. Luego, con dos bucles, definimos las partes de la imagen, tanto horizontales como verticales. En el bucle interno notamos que, usando la librería de clases de Microsoft .Net, en Silverlight po- demos crear nuestras propias imágenes. En este caso, con la siguiente instrucción: imagenes[n] = new Image(); Esta imagen es configurada con sus dimensiones y posición. Pero lo importante es representado por el siguiente código: RectangleGeometry r = new RectangleGeometry(); r.Rect = new Rect((x * 100), (y * 100), 100, 100); imagenes[n].Clip = r; En él, creamos un nuevo rectángulo de 100 pixeles de ancho por 100 pixeles de alto, desplazándolo una cantidad en X y otra en Y sobre la imagen previamente cargada. Pensemos en esta acción como si estuviéramos enfocando sólo parte de una imagen más grande, en la cual desplazamos un rectángulo de visión por sobre una sola sec- ción de 100 pixeles de ancho por 100 pixeles de alto. Acto seguido, asignamos este rectángulo a la propiedad Clip de la imagen. Recordaremos esta propiedad vista en el capítulo anterior, cuando trabajábamos con videos e InkPresenter. Esta propiedad li- mitará el área de visión de la imagen sólo al rectángulo previamente creado. Al final del método ya descrito, encontramos la llamada a dos métodos más, uno para mez- clar o barajar las imágenes y otro para dibujar el tablero de juego en el estado actual. private void barajar() { for (int i = 0; i 15; i++) { Silverlight desde C# 225 07_Silverlight.qxp 9/30/09 1:35 PM Page 225
  • 228.
    tablero[i] = i; } Randomrandomizador = new Random(System.DateTime.Now.Second); for (int i = 0; i 100; i++) { int numero1 = randomizador.Next(15); int numero2 = randomizador.Next(15); if (numero1 != numero2) { int temporal = tablero[numero1]; tablero[numero1] = tablero[numero2]; tablero[numero2] = temporal; } } tablero[15] = -1; } private void dibujarTablero() { int x = 0; int y = 0; for (int i = 0; i 15; i++) { x = i / 4; y = i % 4; if (tablero[i] = 0) { vectorCanvas[tablero[i]].SetValue(Canvas.TopProperty, Convert.ToDouble(y * 100)); vectorCanvas[tablero[i]].SetValue(Canvas.LeftProperty, Convert.ToDouble(x * 100)); } } } El método barajar() mezclará de forma aleatoria las imágenes, creando un nue- vo tablero. Por otro lado, el método dibujarTablero() posicionará cada una de las imágenes sobre la base base del tablero actual. El resultado de esto podemos ver- lo en la Figura 2, que aparece en la próxima página. 7. INTERCONEXIÓN 226 07_Silverlight.qxp 9/30/09 1:35 PM Page 226
  • 229.
    Figura 2. Laimagen desarmada y lista para que iniciemos el juego. El paso final es el de darle movimiento e interacción con el usuario. Así, cada vez que el usuario presione una de las imágenes, ésta deberá ocupar el espacio en blanco conti- guo, si lo hubiere, y dejar su espacio libre para que otra imagen pueda ocuparlo. private void verificarGanador() { bool tableroCompleto = true; for (int i = 0; i 15; i++) { if (i != tablero[i]) { tableroCompleto = false; break; } } if (tableroCompleto) { //Tenemos un ganador! this.textblockGanador.Visibility = Visibility.Visible; } } private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Silverlight desde C# 227 07_Silverlight.qxp 9/30/09 1:35 PM Page 227
  • 230.
    Canvas canvas =sender as Canvas; int identificadorCanvas = -1; int espacioTablero = -1; int espacioVacio = -1; for (int i = 0; i 16; i++) { if (canvas == vectorCanvas[i]) { identificadorCanvas = i; break; } } for (int i = 0; i 16; i++) { if (tablero[i] == identificadorCanvas) { espacioTablero = i; } else if (tablero[i] == -1) { espacioVacio = i; } } if ((espacioTablero == espacioVacio + 1) || (espacioTablero == espacioVacio - 1) || (espacioTablero == espacioVacio + 4) || (espacioTablero == espacioVacio - 4)) { int x = espacioVacio / 4; int y = espacioVacio % 4; 7. INTERCONEXIÓN 228 _` Curiosamente, uno de los sitios más populares para la visualización de videos, YouTube, usó los servicios de streaming de Silverlight para transmitir los eventos en vivo de March Madness. Es- tos eventos pueden ser vistos en la siguiente dirección: www.youtube.com/marchmadness. EL USO DE SILVERLIGHT EN LA WEB 07_Silverlight.qxp 9/30/09 1:35 PM Page 228
  • 231.
    vectorCanvas[identificadorCanvas].SetValue(Canvas.TopProperty, Convert.ToDouble(y * 100)); vectorCanvas[identificadorCanvas].SetValue(Canvas.LeftProperty, Convert.ToDouble(x* 100)); tablero[espacioVacio] = identificadorCanvas; tablero[espacioTablero] = -1; verificarGanador(); } } Podemos notar que el evento donde se captura el presionado del mouse fue en- lazado de manera manual en la inicialización de la aplicación Silverlight mediante el código que vemos a continuación: vectorCanvas[n].MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown); Debido a eso, esta acción será capturada por el método antes descrito; método que podemos ver en la siguiente línea: private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { ... ... En este método, se identifica qué objeto originó el evento de presionado del botón del mouse, buscando en la lista de objetos Canvas cuál concuerda con el que ejecutó el Silverlight desde C# 229 , Sólo con agregar un poco más de funcionalidad al ejemplo planteado, podríamos tener un juego aún más complejo. Pensemos en la posibilidad de adicionar una lista de imágenes de las que se- leccionar, modificar la dificultad agregando más divisiones a la imagen, etcétera. Nuestro único límite es la imaginación. UN PASO MÁS ALLÁ 07_Silverlight.qxp 9/30/09 1:35 PM Page 229
  • 232.
    evento. De estaforma, es posible acceder a sus propiedades, incluida su posición, y si está contiguo a un espacio en blanco. Al cumplir esta última característica, la imagen se moverá a ese lugar y se verificará si el tablero se ha formado de manera completa. Figura 3. Nuestro tablero de juego una vez movidas algunas piezas. WebClient El objeto WebClient nos da la posibilidad de enviar y recibir información de for- ma asíncrona desde y hacia cualquier destino conformado por una dirección URL (Uniform Resource Locator o en castellano, localizador uniforme de recursos). Con WebClient podríamos, por ejemplo, leer información de texto que se encuentre en cualquier parte de una web, o conocer noticias en formato RSS (Really Simple Syndication, o en castellano, distribución simple de contenido). De igual forma, podríamos consumir cualquier otro tipo de información que nos retornara algu- na forma de texto desde la Web. En el siguiente ejemplo, crearemos un lector de noticias en formato RSS, haciendo uso del objeto WebClient y XLinQ para ma- nipular las consultas sobre el contenido. Como primera instancia, crearemos los controles XAML donde se mostrarán los resultados de la consulta. UserControl xmlns:data=”clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data” x:Class=”Capitulo7WebClient.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”400” Height=”300” 7. INTERCONEXIÓN 230 07_Silverlight.qxp 9/30/09 1:35 PM Page 230
  • 233.
    Grid x:Name=”LayoutRoot” Background=”White” data:DataGridx:Name=”RssFeed” AutoGenerateColumns=”True”/data:DataGrid /Grid /UserControl En este ejemplo, usaremos un control DataGrid para mostrar la lista de registros que obtengamos después de haber consultado la fuente RSS. El siguiente paso es hacer uso del objeto WebClient para lanzar una petición asíncrona a la fuente RSS y tomar el resultado por mostrar. public Page() { InitializeComponent(); WebClient conectorWeb = new WebClient(); Uri direccionRSS = new Uri(“http://feeds2.feedburner.com/redusers”); conectorWeb.Encoding = Encoding.UTF8; conectorWeb.DownloadStringCompleted += new DownloadStringCompletedEventHandler(conectorWeb_DownloadStringCompleted); conectorWeb.DownloadStringAsync(direccionRSS); } Al comienzo, creamos un objeto WebClient que usaremos para conectarnos a la fuen- te RSS. También es necesaria una instancia del objeto Uri. Este objeto representa una dirección URL física y la utilizaremos para especificar el origen de la fuente de datos de la que consumiremos la información. WebClient posee una serie de even- tos que se dispararán sobre la base de las acciones que realicemos. • DownloadProgressChanged: se disparará en el momento en el que una llamada asín- crona de descarga de contenidos pueda transferir toda o parte de la información. • DownloadStringCompleted: se ejecuta siempre que un elemento descargado de ma- nera asíncrona se ha descargado por completo. • OpenReadCompleted: ocurre cuando una acción de lectura de un recurso de ma- nera asíncrona se ha completado. • OpenWriteCompleted: se disparará cuando exista una operación de apertura de un archivo para escribir en él y se haya completado esta acción. • UploadProgressChanged: evento que marca cuando parte de una operación de en- vío de información ha transferido todo o una porción de los datos. Silverlight desde C# 231 07_Silverlight.qxp 9/30/09 1:35 PM Page 231
  • 234.
    • UploadStringCompleted: ocurrecuando finaliza una acción de envío de información. • WriteStreamClosed: en el momento en que una operación de escritura se ha com- pletado, este evento se ejecutará. De la lista anterior, usaremos el evento DownloadStringCompleted para que nos avise cuándo la información se descargó por completo. Al ejecutar el código, podemos ver cómo este evento trae la información desde la fuente. Figura 4. En esta imagen, vemos el modo de depuración, con los resultados desde la fuente RSS. A continuación, colocaremos el siguiente código dentro del método del evento DownloadStringCompleted. private void conectorWeb_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { XDocument documentoXML = XDocument.Parse(e.Result.ToString()); var RSS = from fuentes in documentoXML.Descendants(“item”) select new EntidadRSS { Titulo = (string)fuentes.Element(“title”), Descripcion = (string)fuentes.Element(“description”), Link = (string)fuentes.Element(“link”) }; 7. INTERCONEXIÓN 232 07_Silverlight.qxp 9/30/09 1:35 PM Page 232
  • 235.
    this.RssFeed.ItemsSource = RSS; } Unavez que la descarga del contenido es ejecutada, tomaremos este contenido desde los argumentos del evento. El objeto e posee una propiedad llamada Result (resulta- dos), donde se encontrará el contenido de la descarga. Este contenido es asignado a un objeto del tipo XDocument, objeto que puede administrar XML para facilitar su manipulación. Por último, mediante una consulta XLinQ, se toman los datos im- portantes como título, descripción e hipervínculo de acceso a la noticia, alojando todos los resultados dentro de una colección de objetos del tipo EntidadRSS. Ésta es una entidad que creamos para este caso y que podemos ver a continuación. public class EntidadRSS { public string Titulo { get; set; } public string Descripcion { get; set; } public string Link { get; set; } } Figura 5. Las fuentes RSS cargadas en la grilla. Enviar información Así como hemos podido obtener información desde una fuente de datos remota, es posible enviar información hacia la fuente y esperar una respuesta basada en esto. Po- demos hacer uso del mismo modelo antes planteado, pero adicionándole parámetros Silverlight desde C# 233 07_Silverlight.qxp 9/30/09 1:35 PM Page 233
  • 236.
    que se incluiránen el envío de la información. Esta información podrá ser maneja- da por el destino, se analizará y, según ella, se generará una salida para visualizar en la aplicación Silverlight. Como primer paso, crearemos una aplicación Silverlight que incluya por defecto un sitio web de prueba (para recordar cómo hacerlo, podemos ver otra vez el capítulo 3). Crearemos un nuevo sitio web junto con la aplicación Silverlight para facilitarnos las pruebas de este ejemplo. Una vez creado el proyecto, tendremos que ver una estructura similar a la planteada en la siguiente figura. Figura 6. Aplicación Silverlight y sitio web en la misma solución de proyecto. Utilizaremos el sitio web existente para que actúe como recolector de mensajes, el que leerá la información enviada por la aplicación Silverlight y devolverá una res- puesta para mostrar en ella. Implementaremos HttpHandler (manejadores web) para que representen nuestros puntos de entrada de datos. Para lograr esto, dentro del archivo Web.Config del sitio web, tendremos que agregar el manejador en cues- tión. Junto con los manejadores creados por defecto, adicionaremos el nuestro. httpHandlers remove verb=”*” path=”*.asmx”/ add verb=”*” path=”capturaDeInformacion.aspx” type=”Capitulo7Posting.Web.ManejadorHTTP, Capitulo7Posting.Web”/ add verb=”*” path=”*.asmx” validate=”false” type=”System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35”/ add verb=”*” path=”*_AppService.axd” validate=”false” 7. INTERCONEXIÓN 234 07_Silverlight.qxp 9/30/09 1:35 PM Page 234
  • 237.
    type=”System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35”/ addverb=”GET,HEAD” path=”ScriptResource.axd” type=”System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35” validate=”false”/ /httpHandlers En el HttpHandler declarado, éste tomará todas las peticiones que se realicen dentro de nuestro sitio web bajo el nombre de capturaDeInformacion.aspx. Todas las peticio- nes que se realicen bajo este nombre serán redirigidas a la clase ManejadorHTTP, por lo que deberemos adicionar esta clase y su código respectivo a nuestra aplicación web. public class ManejadorHTTP : IHttpHandler { public bool IsReusable { get { return true; } } public void ProcessRequest(HttpContext context) { context.Response.ContentType = “text/xaml”; context.Response.Write(“Canvas xmlns=’http://schemas.microsoft.com/client/2007’ “ + “xmlns:x=’http://schemas.microsoft.com/winfx/2006/xaml’” + Silverlight desde C# 235 RRR Un HttpHandler nos otorga la posibilidad de capturar entradas HTTP a nuestro sitio web bajo un nombre específico, sin tener que contar necesariamente con la página web física. Para poder usar HttpHandler, es necesario especificar el nombre de la clase que manejará la petición, así como el espacio de nombre que la contiene. HTTPHANDLER 07_Silverlight.qxp 9/30/09 1:35 PM Page 235
  • 238.
    “TextBlock Foreground=’black’ Padding=’10’FontSize=’20’Hola “ + context.Request.QueryString[“Texto”] + “/TextBlock/Canvas”); } } Como vemos en el código anterior, la clase ManejadorHTTP implementa la interfaz IHttpHandler, definiéndola como un manejador HTTP. Esta interfaz implementa dos métodos, teniendo como importante el llamado ProcessRequest. Este método presenta un comportamiento similar al de un evento y se disparará cada vez que se haga una petición web que sea capturada por el manejador HTTP definido con anterioridad. En el objeto context, podremos encontrar toda la información refe- rente a la petición HTTP, incluso los valores enviados por el cliente. Al mismo tiempo, todo resultado que escribamos dentro del objeto context será enviado de vuelta al cliente, por lo que podremos crear cualquier tipo de contenido y enviar- lo de manera directa a nuestra aplicación Silverlight. Como vemos en las dos líneas de código de este método, la primera redefine el tipo de salida, especificando que ésta será del tipo texto plano y con formato XAML. La siguiente línea crea el texto de un control Canvas que contiene un control TextBlock que muestra un mensaje. Este mensaje incluye una palabra, más lo enviado por el usuario. De esta forma, terminamos de definir el punto de contacto de nuestra aplicación Silverlight y un servicio o recolector de mensajes distante. Del lado de Silverlight, lo primero que hacemos es crear el código XAML para contener esta información y para darle la posibilidad al usuario de enviarla. Veámoslo a continuación: UserControl x:Class=”Capitulo7Posting.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”400” Height=”300” xmlns:d=”http://schemas.microsoft.com/expression/blend/2008” xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006” mc:Ignorable=”d” Grid x:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition Height=”0.16*”/ RowDefinition Height=”0.84*”/ /Grid.RowDefinitions 7. INTERCONEXIÓN 236 07_Silverlight.qxp 9/30/09 1:35 PM Page 236
  • 239.
    Grid.ColumnDefinitions ColumnDefinition/ /Grid.ColumnDefinitions TextBox Margin=”57,8,0,18” Text=””TextWrapping=”Wrap” Width=”143” HorizontalAlignment=”Left” x:Name=”textBox”/ Button Click=”Button_Click” HorizontalAlignment=”Right” Margin=”0,8,153,18” Content=”Enviar” d:LayoutOverrides=”Width, Height”/ TextBlock HorizontalAlignment=”Left” Margin=”8,14,0,18” Text=”Mensaje:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ StackPanel x:Name=”contenedor” Margin=”8,8,8,8” Grid.Row=”1”/ /Grid /UserControl Figura 7. Aplicación Silverlight que consumirá un elemento distante. Si bien ya hemos visto este código en diferentes ocasiones, debemos destacar la pre- sencia del control StackPanel al final del código XAML. En este control, aplicaremos la respuesta del elemento HttpHandler ya creado. Por último, creamos el código que manejará la petición y creará el control Silverlight basado en su código XAML. private void Button_Click(object sender, RoutedEventArgs e) { WebClient conectorWeb = new WebClient(); Silverlight desde C# 237 07_Silverlight.qxp 9/30/09 1:35 PM Page 237
  • 240.
    Uri direccionRSS =new Uri(“http://localhost:1870/capturaDeInformacion.aspx?Texto=” + this.textBox.Text); conectorWeb.Encoding = Encoding.UTF8; conectorWeb.DownloadStringCompleted += new DownloadStringCompletedEventHandler(conectorWeb_DownloadStringCompleted); conectorWeb.DownloadStringAsync(direccionRSS); } void conectorWeb_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { Canvas control = XamlReader.Load(e.Result.ToString()) as Canvas; this.contenedor.Children.Add(control); } En el código anterior, vemos cómo el valor de la caja de texto es pasada en la ruta de navegación creada por el objeto Uri. Uri direccionRSS = new Uri(“http://localhost:1870/capturaDeInformacion.aspx?Texto=” + this.textBox.Text); Esto garantizará que el HttpHandler pueda leer el valor introducido por el usua- rio y actuar en consecuencia. En el código, aparece un nuevo objeto que todavía no habíamos visto. Este objeto XamlReader permite crear controles Silverlight a partir del texto representativo en XAML. Este control carga el texto devuelto por el HttpHandler y crea una nueva instancia del control en cuestión. Finalmente, adi- cionamos este resultado a la lista de controles hijo del StackPanel. 7. INTERCONEXIÓN 238 RRR Cuando usamos las entradas del usuario como parámetros en nuestras aplicaciones, debere- mos tener sumo cuidado. Las entradas de los usuarios siempre deben ser comprobadas para que no contengan caracteres o código ejecutable que pueda generar comportamientos no dese- ados. Cross Site Scripting o SQL Injection son dos de las vulnerabilidades más comunes. SEGURIDAD SOBRE PARÁMETROS 07_Silverlight.qxp 9/30/09 1:35 PM Page 238
  • 241.
    Figura 8. Elresultado devuelto por el HttpHandler y el nuevo control creado incluido dentro del StackPanel. Como hemos podido comprobar, Silverlight puede salir fuera de su contenedor para comunicarse con otras aplicaciones conectadas a la red. Si bien sólo hemos consumi- do información de páginas web, es posible hacerlo de servicios web, así como de la nueva plataforma de comunicación de Microsoft, WCF (Windows Communication Foundation). Veremos estas alternativas, más adelante, en este mismo capítulo. ALMACENAMIENTO AISLADO Silverlight posee un mecanismo para poder guardar información de manera local en el cliente que esté ejecutando la aplicación. Si tenemos experiencia en el desarrollo web, podríamos asociar la idea de este almacenamiento al utilizado por las cookies, elementos que son almacenados y administrados por el navegador del cliente, usados por lo general para dejar alguna información en ese equipo y que serán consultadas en posteriores ocasiones. Pero si bien conceptualmente resulta algo similar, el alma- cenamiento aislado en Silverlight presenta otras características. Pensemos en esta funcionalidad como en la posibilidad de tener una parte del disco duro de la má- quina cliente para almacenar de manera segura información desde nuestra aplicación Silverlight. Podríamos, por ejemplo, cargar archivos desde el cliente, almacenarlos en este espacio reservado y usarlos luego en nuestra aplicación. De esta manera, le aho- rramos al usuario el tiempo de carga y evitamos pedirle que haga el mismo trabajo todas las veces que use la aplicación. Por otro lado, esta característica trae consigo un concepto de seguridad. Tengamos en cuenta que los navegadores web restringen el Almacenamiento aislado 239 07_Silverlight.qxp 9/30/09 1:35 PM Page 239
  • 242.
    acceso a archivosen el equipo del usuario. De esta forma, se aseguran de que dife- rentes aplicaciones y sitios web no puedan causar daño alguno al sistema operativo del usuario. Debido a este impedimento, y para no romper esta condición, Silverlight nos permite crear y leer información desde el equipo del usuario de manera contenida, sin poder acceder más allá del espacio reservado para la aplicación. Implementar el almacenamiento aislado Para poder usar almacenamiento aislado es necesario incluir el espacio de nombres System.IO.IsolatedStorage en nuestro código. Una vez que lo hemos adicionado, po- dremos acceder de manera más fácil a los objetos que administran esta funcionalidad. Debido a que Silverlight es el que nos proveerá y administrará el espacio reservado pa- ra nuestra aplicación, deberemos recuperar este espacio antes de poder leer o escribir cualquier información en él. Este espacio de nombre tiene tres elementos básicos: • IsolatedStorageFile: representa el almacén donde se encuentran todos los archivos correspondientes a la aplicación y al usuario. Incluye archivos y directorios. • IsolatedStorageFileStream: es utilizado para leer o escribir los distintos archivos dentro del almacén de datos. • IsolatedStorageSettings: es un diccionario de datos representado por un par llave/ valor, que va a ser almacenado en el almacén de datos. Obtener el espacio designado para nuestra aplicación es simple. Podemos hacerlo de la manera que vemos a continuación: IsolatedStorageFile almacen = IsolatedStorageFile.GetUserStoreForApplication(); Esto retornará una referencia al directorio y al espacio designado para nuestra apli- cación. Una vez que tenemos esta referencia, todo lo que leamos o escribamos pasa- rá por este espacio reservado. Si tenemos experiencia en el manejo de archivos bajo Microsoft .Net, notaremos que el manejo del espacio reservado en Silverlight posee algunos puntos de contacto con su superior, teniendo diferentes métodos para cre- ar, borrar y leer archivos, así como para crear o borrar directorios. Los siguientes son los métodos que tenemos a nuestra disposición para trabajar con el almacén aislado: • CreateDirectory: crea un nuevo directorio dentro del almacén. Podremos espe- cificar un nombre para el directorio. • DeleteDirectory: borra un directorio del almacén. • CreateFile: crea un nuevo archivo, retornando un objeto IsolatedStorageFileStream. 7. INTERCONEXIÓN 240 07_Silverlight.qxp 9/30/09 1:35 PM Page 240
  • 243.
    • DeleteFile: eliminaun archivo del almacén. • Remove: se encarga de eliminar por completo el almacén junto con todos sus directorios y archivos contenidos. • OpenFile: este método abre un archivo guardado en el almacén y retorna un ob- jeto IsolatedStorageFileStream. • FileExists: verifica la existencia de un archivo en particular. Es útil en casos en los que necesitemos saber si un archivo determinado ya fue creado o no. • DirectoryExists: verifica la existencia de un directorio en particular. • GetFileNames: devuelve un vector con los nombres de los archivos existentes en el almacén o en un directorio específico de éste. • GetDirectoryNames: este método retorna un vector que contiene los nombres de los directorios dentro del almacén. Para poder crear un nuevo archivo dentro del almacén, escribiremos lo siguiente: IsolatedStorageFile almacen; public Page() { InitializeComponent(); almacen = IsolatedStorageFile.GetUserStoreForApplication(); } private void Button_Click(object sender, RoutedEventArgs e) { using (IsolatedStorageFileStream archivo = almacen.CreateFile(“archivo.txt”)) { StreamWriter streamWriter = new StreamWriter(archivo); streamWriter.Write(DateTime.Now); streamWriter.Close(); } this.mensaje.Text = “Se escribió un archivo.”; } Como vemos, para este caso se inicializa el almacén y el evento que disparará el bo- tón. Usaremos este almacén para crear un archivo llamado archivo.txt, escribiendo en él la fecha actual. En la Figura 9, ubicada en la página siguiente, podemos ob- servar el resultado obtenido con lo que hemos realizado. Almacenamiento aislado 241 07_Silverlight.qxp 9/30/09 1:35 PM Page 241
  • 244.
    Figura 9. Elarchivo fue creado con éxito y se envía un mensaje al usuario para informarlo de este hecho. Así como hemos podido crear un nuevo archivo y guardar información en él, también tenemos la posibilidad de recuperar esa información y manipularla. Po- dremos hacer esto con el siguiente código: private void Button_Click_1(object sender, RoutedEventArgs e) { string contenido = string.Empty; using (IsolatedStorageFileStream archivo = almacen.OpenFile(“archivo.txt”,FileMode.OpenOrCreate)) { StreamReader streamReader = new StreamReader(archivo); contenido = streamReader.ReadToEnd(); streamReader.Close(); 7. INTERCONEXIÓN 242 , Es importante usar el método Close() después de cada operación con archivos para marcar el fin de su uso y así liberarlo. Si no lo hiciéramos, el archivo podría quedar tomado por la aplicación y, al tratar de accederlo nuevamente, obtendríamos un error ya que el archivo está en uso. CIERRE DE ARCHIVOS 07_Silverlight.qxp 9/30/09 1:35 PM Page 242
  • 245.
    } this.mensaje.Text = “Unarchivo leído. Contenido: “ + contenido; } En este caso, el contenido del archivo es recuperado y almacenado en una variable tem- poral para luego mostrar su valor en un mensaje, como vemos en la siguiente figura. Figura 10. El archivo fue leído y su contenido mostrado. Notemos que, una vez que abrimos el archivo para leerlo, podemos especificar su modo de apertura mediante la enumeración FileMode. Esta enumeración po- see algunas características especiales: • CreateNew: especifica que se creará un nuevo archivo si no existiera anteriormente. • Create: especifica que se creará un nuevo archivo. Si el archivo ya existe, entonces éste será sobrescrito, y se perderán los datos del anterior. • Open: abrirá un archivo existente. Si el archivo no existe, será arrojado un error. • OpenOrCreate: abrirá o creará un archivo basado en su existencia. Si el archivo exis- te, lo abrirá. Si no, creará uno nuevo. • Append: abre un archivo existente. Al hacerlo, desplazará el punto de lectura hacia el fin del archivo. De esta forma, lo que escribamos en él se hará al final, y adicio- nará elementos al archivo existente. Ya hemos creado y leído el archivo. Pero como dijimos, es posible hacer con él todas las operaciones básicas con archivos. En este caso, borraremos el archivo escribiendo el código que aparece en la próxima página: Almacenamiento aislado 243 07_Silverlight.qxp 9/30/09 1:35 PM Page 243
  • 246.
    private void Button_Click_2(objectsender, RoutedEventArgs e) { almacen.DeleteFile(“archivo.txt”); this.mensaje.Text = “Se eliminó el archivo.”; } Figura 11. El archivo fue eliminado del almacén. Todos los archivos son almacenados en una ubicación específica dentro del sistema ope- rativo. En este caso, se ubican en las carpetas que contienen información del usuario. Figura 12. Ubicación del archivo creado en el almacén. 7. INTERCONEXIÓN 244 07_Silverlight.qxp 9/30/09 1:35 PM Page 244
  • 247.
    Capacidad de almacenamiento Pordefecto, el espacio disponible para el almacenaje de datos es de 1 megabyte. Por supuesto, es posible que en determinadas circunstancias necesitemos más es- pacio. Debido a que, como comentamos antes, Silverlight respeta el modelo de seguridad propuesto para el desarrollo web, no podremos aumentar la cantidad de espacio sin la autorización previa por parte del usuario. Pensemos que, de po- der pasar por alto este tipo de validaciones, estaríamos en condiciones de vulne- rar la seguridad del usuario. Imaginemos que colmamos el total del espacio del disco duro del cliente sin que éste se entere. Definitivamente sería un problema y, por tal motivo, el usuario debe estar al tan- to de esa acción antes de que nosotros podamos utilizar más del espacio que es provisto por defecto. Es posible verificar e incrementar la cantidad de espacio disponible escribiendo el siguiente código: private void Button_Click_3(object sender, RoutedEventArgs e) { if (almacen.AvailableFreeSpace 2000 * 1024) { if (almacen.IncreaseQuotaTo( almacen.Quota + (2000 * 1024) - almacen.AvailableFreeSpace)) { this.mensaje.Text = “El espacio disponible es ahora de “ + (almacen.Quota + (2000 * 1024)).ToString() + “ más.”; } else { this.mensaje.Text = “Usted no aceptó el incremento de tamaño.”; } } } Almacenamiento aislado 245 RRR Es necesario verificar el tamaño del almacén antes de hacer la petición de incremento. Si la cuo- ta actual fuera del mismo tamaño o superior a la que estamos pidiendo, obtendrímos un error con la advertencia de que la cuota existente es igual o superior a la que reclamamos. TAMAÑO DEL ALMACÉN 07_Silverlight.qxp 9/30/09 1:35 PM Page 245
  • 248.
    El código anteriorintentará pedir 2 megabytes adicionales a los ya usados. Si bien aún no hemos usado nada del primer megabyte del espacio por defecto, este código intentará incrementar en 2 megabytes ese espacio. Al ejecutar el código, podemos ver la ventana emergente que nos pide autorización para incrementar el espacio dispo- nible, como se muestra en la figura siguiente. Figura 13. Petición para incremento de la cuota en el almacén. Si necesitamos conocer cuánto espacio utiliza la aplicación Silverlight, es posible ac- ceder a esta información presionando el botón derecho del mouse y seleccionando la opción Silverlight en el menú desplegable. Al hacerlo, veremos todas las propie- dades de la aplicación en ejecución. En la última pestaña, aparecerán las propieda- des relacionadas con el almacenamiento aislado, donde es posible saber el espacio consumido actualmente y hasta cuánto podría crecer, además de poder liberar este espacio con las opciones de esta ventana. Figura 14. Opciones de la aplicación Silverlight donde es posible ver el espacio de almacenamiento consumido y el disponible. 7. INTERCONEXIÓN 246 07_Silverlight.qxp 9/30/09 1:35 PM Page 246
  • 249.
    Almacenar configuraciones Es posibleque necesitemos almacenar valores como textos u objetos complejos, pe- ro sin la necesidad de tener que crear un archivo por nuestra cuenta. Podríamos, por ejemplo, guardar la lista de productos de un carrito de compras o el nombre del usuario que está usando la aplicación, pero sin llegar a tener que generar código para manipular archivos almacenados de forma física. La característica de almacena- miento aislado nos permite, además de la manipulación de archivos, la posibilidad de almacenar tipos de datos de manera simple y rápida, que se pueda recuperar en cualquier momento de la misma forma en la que fueron almacenados. Esto quiere decir que, si guardáramos un objeto personalizado, recuperaríamos el mismo obje- to. Crearemos dos botones y una caja de texto para permitir al usuario introducir texto, que luego guardaremos y recuperaremos utilizando este mecanismo. TextBox VerticalAlignment=”Bottom” Text=”” TextWrapping=”Wrap” Margin=”121,0,117,72” Height=”25” x:Name=”aplicacion”/ TextBlock HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Text=”Valor de aplicación:” TextWrapping=”Wrap” d:LayoutOverrides=”Height” Margin=”8,0,0,76”/ Button Click=”Button_Click_4” HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Content=”Almacenar” d:LayoutOverrides=”Width” Margin=”8,0,0,29”/ Button Click=”Button_Click_5” HorizontalAlignment=”Left” VerticalAlignment=”Bottom” Content=”Recuperar” Margin=”76,0,0,29”/ Como siguiente paso, tomaremos el valor de la caja de texto y la asignaremos a una variable de configuración dentro del almacén. private void Button_Click_4(object sender, RoutedEventArgs e) { IsolatedStorageSettings.ApplicationSettings[“Texto”] = Almacenamiento aislado 247 RRR El almacenamiento aislado tiene un comportamiento diferente al de las cookies. Éste no se ma- neja por navegador, sino por usuario. Esto quiere decir que acceder a la misma aplicación con diferentes navegadores utilizará el mismo espacio reservado, sin importar quién creó inicial- mente este espacio de almacenamiento. EL ALCANCE DEL ALMACENAMIENTO AISLADO 07_Silverlight.qxp 9/30/09 1:35 PM Page 247
  • 250.
    this.aplicacion.Text; this.aplicacion.Text = “”; } Estavariable no necesita existir previamente y será creada en el momento en el que sea asignada por primera vez. Si la variable ya existiera, su contenido será rempla- zado con el nuevo valor. En el ejemplo anterior, el nombre de la variable es Texto y contendrá el valor introducido por el usuario. A continuación, podremos recuperar este valor con el siguiente código: private void Button_Click_5(object sender, RoutedEventArgs e) { this.aplicacion.Text = IsolatedStorageSettings.ApplicationSettings[“Texto”].ToString(); } ApplicationSettings retornará un tipo de datos Object, por lo que es necesario trans- formarlo al tipo conocido, en este caso un String, para poder reasignarlo a la caja de texto. Como podemos ver en la figura que aparece debajo, los resultados almace- nados desde un navegador son visibles en el otro. Figura 15. La variable almacenada por el usuario en el navegador de la izquierda, es leída desde la aplicación Silverlight en el navegador de la derecha. Como dijimos, es posible almacenar cualquier objeto o lista de éstos dentro de es- tas variables de configuración. De cualquier manera, es necesario que tengamos en cuenta que sólo podrán ser almacenados aquellos elementos que contengan la cua- lidad de ser serializados. Esto quiere decir que podremos almacenar elementos, 7. INTERCONEXIÓN 248 07_Silverlight.qxp 9/30/09 1:35 PM Page 248
  • 251.
    cuyos tipos dedatos puedan ser transformados a XML. Para ilustrar esta posibili- dad, crearemos una colección de entidades, alojándolas primero en una variable de configuración que luego recuperaremos para llenar un control DataGrid. UserControl xmlns:data=”clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data” x:Class=”Capitulo7AlmacenamientoObjetos.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”400” Height=”300” xmlns:d=”http://schemas.microsoft.com/expression/blend/2008” xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006” mc:Ignorable=”d” Grid x:Name=”LayoutRoot” Background=”White” Button HorizontalAlignment=”Left” Margin=”8,8,0,0” VerticalAlignment=”Top” Content=”Cargar lista”/ Button HorizontalAlignment=”Left” Margin=”82,8,0,0” VerticalAlignment=”Top” Content=”Mostrar lista” d:LayoutOverrides=”HorizontalAlignment”/ data:DataGrid Margin=”0,51,0,0” x:Name=”grillaDeDatos”/data:DataGrid /Grid /UserControl El siguiente paso es crear una clase que contenga nuestra entidad y sirva para alma- cenar datos (podemos ver un ejemplo de esto en los capítulos 3 y 4). En el momento en el que se ejecute el evento Click del botón, cargaremos una lista de nuestras entidades y las almacenaremos en una variable de configuración. private void Button_Click(object sender, RoutedEventArgs e) { ListProductos productos = new ListProductos(); productos.Add(new Productos() { Producto = “Producto 1”, Cantidad = 10, Categoria = “Categoria 1”, Precio = 100 }); Almacenamiento aislado 249 07_Silverlight.qxp 9/30/09 1:35 PM Page 249
  • 252.
    productos.Add(new Productos() { Producto =“Producto 2”, Cantidad = 20, Categoria = “Categoria 1”, Precio = 50 }); //Agregar tantas como sean necesarias. IsolatedStorageSettings.ApplicationSettings[“ListaProductos”] = productos; } Como podemos ver, se agrega la lista de productos sin realizarle ninguna modi- ficación. Esto se debe a que todos los elementos internos de la entidad pueden ser transformados a XML sin problema alguno. Finalmente, en el evento del se- gundo botón, leemos estos valores y los asignamos al control DataGrid. Para eso, el código es el que aparece a continuación: private void Button_Click_1(object sender, RoutedEventArgs e) { this.grillaDeDatos.ItemsSource = IsolatedStorageSettings.ApplicationSettings[“ListaProductos”] as ListProductos; } Notemos que utilizamos la palabra reservada AS para transformar el resultado de la variable de configuración al tipo conocido, o sea, una lista genérica de nuestra en- tidad. El resultado de estas dos acciones las podemos ver en la Figura 16. 7. INTERCONEXIÓN 250 RRR Serializar información no es una tarea trivial. Podemos encontrarnos atascados fácilmente al momento de querer transformar nuestros objetos en distintos formatos de almacenamiento. Al aplicar este mecanismo, también podremos realizar acciones con la información. En http://msdn.microsoft.com/es-es encontraremos más información. SERIALIZACIÓN 07_Silverlight.qxp 9/30/09 1:35 PM Page 250
  • 253.
    Figura 16. DataGridcargado con datos tomados desde una variable de configuración. OpenFileDialog OpenFileDialog es un control homónimo del usado en aplicaciones de escritorio. Per- mite abrir una ventana donde el usuario deberá seleccionar un archivo de su equipo, archivo que podremos leer y manipular. Encontramos este tipo de comportamiento en páginas web en las que podemos seleccionar un archivo, como fotografías, para alojar- las en un servidor. El código para crear un objeto del tipo OpenFileDialog es: OpenFileDialog ventanaDialogo = new OpenFileDialog(); Para abrir la ventana de selección, deberemos llamar al método ShowDialog(). Este método retornará el valor True cuando el usuario aplique los archivos seleccionados. OpenFileDialog ventanaDialogo = new OpenFileDialog(); ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt”; ventanaDialogo.Multiselect = true; if (ventanaDialogo.ShowDialog() == true) { ... En el código anterior, también podemos notar que es posible definir el filtro de los archivos por buscar, así como si se permitirá seleccionar más de un archivo al Almacenamiento aislado 251 07_Silverlight.qxp 9/30/09 1:35 PM Page 251
  • 254.
    mismo tiempo. Elejemplo que vemos a continuación muestra todos los archivos cargados por el usuario en un control ListBox. private void Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog ventanaDialogo = new OpenFileDialog(); ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt”; ventanaDialogo.Multiselect = true; if (ventanaDialogo.ShowDialog() == true) { Liststring listaArchivos = new Liststring(); foreach (FileInfo archivo in ventanaDialogo.Files) { listaArchivos.Add(archivo.Name); } this.listaDeArchivos.ItemsSource = listaArchivos; } } Figura 17. El filtro mostrará sólo archivos con extensión TXT o de texto para seleccionar. Luego de que el usuario selecciona los archivos permitidos por el filtro establecido, todos sus nombres son listados en el control ListBox, como podemos observar en la Figura 18, ubicada en la página siguiente. 7. INTERCONEXIÓN 252 07_Silverlight.qxp 9/30/09 1:35 PM Page 252
  • 255.
    Figura 18. Listade todos los archivos seleccionados por el usuario. Podremos agregar tantos filtros como creamos necesarios. Para lograr esto, modifi- caremos el filtro inicial incluyendo otros, de la siguiente manera: ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt|Imágenes JPG (*.jpg)|*.jpg”; Ahora, tenemos un nuevo tipo disponible para seleccionar en el cuadro de diálogo: Figura 19. Un nuevo filtro agregado a la lista de elementos seleccionables. Almacenamiento aislado 253 07_Silverlight.qxp 9/30/09 1:35 PM Page 253
  • 256.
    Es posible combinarel uso del objeto OpenFileDialog con la funcionalidad de alma- cenamiento aislado. En el siguiente ejemplo, copiaremos los archivos seleccionados por el usuario a una sección del almacén reservado para nuestra aplicación. IsolatedStorageFile almacen; public Page() { InitializeComponent(); almacen = IsolatedStorageFile.GetUserStoreForApplication(); } private void Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog ventanaDialogo = new OpenFileDialog(); ventanaDialogo.Filter = “Archivos de texto (*.txt)|*.txt|Imágenes JPG (*.jpg)|*.jpg”; ventanaDialogo.Multiselect = true; if (ventanaDialogo.ShowDialog() == true) { Liststring listaArchivos = new Liststring(); foreach (FileInfo archivo in ventanaDialogo.Files) { listaArchivos.Add(archivo.Name); using (Stream datosArchivo = archivo.OpenRead()) { using (IsolatedStorageFileStream datosAlmacen = almacen.CreateFile(archivo.Name)) { byte[] buffer = new byte[1024]; int count = 0; do { count = datosArchivo.Read(buffer, 0, buffer.Length); if (count 0) datosAlmacen.Write(buffer, 0, count); } while (count 0); } 7. INTERCONEXIÓN 254 07_Silverlight.qxp 9/30/09 1:35 PM Page 254
  • 257.
    } } this.listaDeArchivos.ItemsSource = listaArchivos; } } Porcada elemento leído desde el diálogo de archivos, crearemos un nuevo archivo en el almacén con el mismo nombre, copiando sus datos de forma bina- ria. Como resultado, podremos ver que los archivos seleccionados previamente fueron copiados a la ruta del almacén. MANEJO DE HILOS Quizás, no estemos familiarizados con el manejo de hilos, también llamados threads por su nombre en inglés. Esta característica es típica de las aplicaciones de escrito- rio, donde es posible ejecutar más de un proceso, función o pieza de código de ma- nera simultánea. Esto quiere decir que podremos tener más de una pieza funcional de código dentro de nuestra aplicación, procesando información de manera paralela. Para entender esto aún más, pensemos en código que podría tomar mucho tiempo en ejecutarse, como modificar una imagen, insertar registros en una base de datos de forma masiva o generar un cálculo matemático de alta complejidad. Estos pro- cesos pueden tomar mucho tiempo en llevarse a cabo, y hacer esperar al usuario hasta que ese proceso finalice antes de que pueda seguir usando nuestra aplica- ción, podría resultar poco práctico. De esta forma, estos procesos de alta com- plejidad podrían ser ejecutados de manera paralela haciendo que, en el momento en el que terminen su ejecución, nos avisen para que podamos continuar con otro tipo de tarea. Silverlight no está exento de esta capacidad, a pesar de tener una fir- ma muy pequeña y estar pensado para que sea liviano y rápido. Manejo de hilos 255 RRR Si bien el uso de hilos puede ser de gran ayuda para la ejecución de tareas en paralelo, de- bemos tener en cuenta que éste no es un recurso inagotable y, por más hilos que creemos y tareas que ejecutemos en paralelo, el rendimiento de nuestra aplicación no será constante. Es importante no abusar de estos elementos en nuestro código. HILOS 07_Silverlight.qxp 9/30/09 1:35 PM Page 255
  • 258.
    El concepto dehilos En los diferentes capítulos ya hemos tenido algunos contactos con el manejo de hi- los. Si bien no hemos creado ni declarado hilos de manera explícita, sí hemos usado objetos que poseen un comportamiento similar. Objetos como Storyboard o Timer son algunos ejemplos de componentes que pueden ejecutar código en un hilo de eje- cución distinto del primario definido por la aplicación, disparando eventos basados en ciertos estímulos ya configurados. Esto es posible debido a que el sistema opera- tivo es el que administra los procesos de cada aplicación que se ejecuta, asignándole un espacio de tiempo para realizar sus tareas. Así, el sistema operativo irá iterando entre cada uno de estos procesos, además de sus propios procesos, y de esta forma permitirá que las aplicaciones no tomen el control absoluto de todo el equipo. Es común que el manejo de hilos pase desapercibido cuando usamos o desarrolla- mos cualquier aplicación, pero pensemos que el hecho de que podamos mover el puntero del mouse y al, mismo tiempo, escuchar música o escribir un documento es gracias a que el sistema operativo, a altísima velocidad, está otorgándole una frac- ción de tiempo a cada una de estas aplicaciones para que puedan realizar sus traba- jos. En el caso de las aplicaciones visuales, todo el manejo de la interfaz visual, así como de la lógica de esa aplicación, se realiza en un único hilo de ejecución. Debi- do a esto, tener una tarea que capte todo el tiempo disponible otorgado por el sis- tema operativo para la ejecución de procesos podría bloquear la interfaz visual, haciendo pensar que la aplicación ha sufrido un problema y que no funcionará correctamente. Para ilustrar esto, veamos el siguiente código: public Page() { InitializeComponent(); ProcesoLargo(); } public void ProcesoLargo() { for (long i = long.MinValue; i = long.MaxValue; i++) { } } El código anterior no es muy complejo, pero el bucle presentado itera entre valores bastante amplios bloqueando por completo el hilo principal de ejecución de la apli- cación, lo que hace que no podamos interactuar con ella hasta que el bucle finalice 7. INTERCONEXIÓN 256 07_Silverlight.qxp 9/30/09 1:35 PM Page 256
  • 259.
    por completo. Comoresultado de la ejecución del código anterior, somos proclives a obtener errores como el que vemos en la siguiente figura. Figura 20. La única alternativa posible es terminar abruptamente la ejecución de la aplicación. Para este tipo de tareas, entonces, lo recomendable sería crear un nuevo hilo de ejecución para que estas líneas de código se ejecuten en paralelo y así no bloquear toda la aplicación. Conozcamos algunas formas de hacerlo. Temporizador Una de las primeras implementaciones provistas por Microsoft .Net Framework que implementan hilos son los temporizadores, también conocidos como Timers por su nombre en inglés. En el caso de Silverlight, tenemos un temporizador especial dentro del espacio de nombres System.Windows.Threading. Este tempori- zador es llamado DispatcherTimer y cumple la función de disparar un evento basa- do en un intervalo dado. DispatcherTimer posee las siguientes propiedades: • Interval: el intervalo representa el tiempo en milisegundos que deberá transcurrir antes de disparar el evento Tick. • Start: inicia el temporizador. Una vez configurado el objeto DispatcherTimer, de- bemos llamar al método Start() para iniciar la ejecución del temporizador. • Stop: detiene la ejecución del temporizador. • Tick: éste es el evento al que deberemos subscribirnos para recibir las alertas disparadas por DispatcherTimer cada vez que transcurra el tiempo configurado en la propiedad Interval que vimos al principio de esta lista. Manejo de hilos 257 07_Silverlight.qxp 9/30/09 1:35 PM Page 257
  • 260.
    Podríamos usar DispatcherTimerpara generar una aplicación tipo reloj, actualizando los minutos o segundos en tiempo real; o en otras implementaciones tales como el envío de información hacia un servicio o página web desde nuestra aplicación Silverlight sin intervención del usuario y, al mismo tiempo, sin bloquear el hilo principal de ejecución de la aplicación. En el siguiente ejemplo, vemos cómo apli- car este temporizador para actualizar el progreso de un control ProgressBar. UserControl x:Class=”Capitulo7Hilos.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” ProgressBar x:Name=”progressBar” VerticalAlignment=”Top” Height=”24” Margin=”23,39,26,0” / /Grid /UserControl Una vez que hemos definido el control ProgressBar, declaramos el temporizador DispatcherTimer y actualizamos el resto del control ProgressBar por cada Tick() ejecutado por el objeto temporizador. DispatcherTimer temporizador; public Page() { InitializeComponent(); temporizador = new DispatcherTimer(); temporizador.Tick += new EventHandler(temporizador_Tick); temporizador.Interval = TimeSpan.FromSeconds(1); temporizador.Start(); } void temporizador_Tick(object sender, EventArgs e) { this.progressBar.Value++; } Como vemos en la Figura 21 de la próxima página, el control ProgressBar es ac- tualizado dentro del rango de tiempo fijado por el control DispatcherTimer. 7. INTERCONEXIÓN 258 07_Silverlight.qxp 9/30/09 1:35 PM Page 258
  • 261.
    Manejo de hilos 259 Figura21. En cada navegador, vemos los diferentes estados del control ProgressBar, actualizado cada un segundo de ejecución. Personalizar los hilos En el caso anterior, donde vimos el objeto DispatcherTimer, éste fue creado para reali- zar una tarea específica: generar su propio proceso o hilo de ejecución y avisarnos cada vez que el tiempo configurado fuera alcanzado. Este comportamiento no nos resultará para nada práctico en casos más específicos o avanzados. Supongamos que necesitamos modificar el comportamiento del control ProgressBar sobre la base del progreso real de una tarea que es ejecutada por una función creada por nosotros. Para estos casos, es po- sible colocar la ejecución de esa función o método en un hilo separado. Esto, como ya dijimos, hará que el hilo principal, aquel que administra la interfaz del usuario, no se bloquee, dándole al usuario una experiencia más agradable al ejecutar la aplicación. private void RealizarProceso() { for (int i = 0; i 100; i++) { this.progressBar.Value = (double)valor; Thread.Sleep(500); } } En el caso anterior, si ejecutáramos el proceso en forma directa, conseguiríamos que la interfaz visual quedara completamente bloqueada, en especial por la línea: Thread.Sleep(500); 07_Silverlight.qxp 9/30/09 1:35 PM Page 259
  • 262.
    Esta línea detendráel hilo de ejecución actual durante medio segundo, por lo que, por cada iteración del bucle, todo el hilo de ejecución se detendrá. Para este caso, es- cribimos esa línea sólo para lograr una sensación de trabajo por parte de la aplicación y no cargar en forma instantánea la barra de progreso. En todo caso, el problema per- siste ya que seguiremos bloqueando el hilo principal de ejecución, a menos que eje- cutemos esta función en un hilo diferente, como vemos en el siguiente código: private void Button_Click(object sender, RoutedEventArgs e) { ThreadStart referenciaProceso = new ThreadStart(RealizarProceso); Thread nuevoHilo = new Thread(referenciaProceso); nuevoHilo.Start(); } Como primer paso, creamos un delegado del tipo ThreadStart, el cual recibe como parámetro el nombre de la función o método que queramos ejecutar de manera asín- crona. El siguiente paso consiste en crear un nuevo hilo de ejecución mediante el uso de la clase Thread y asignarle al parámetro requerido el delegado creado previamen- te. Hasta este punto, sólo hemos creado el ambiente de ejecución del nuevo hilo, por lo que usaremos el método Start() para iniciar el proceso. Si ejecutamos el nuevo proceso tal como lo hemos escrito, veremos que obtendremos un error en la ejecución. Esto se debe a que no es posible, en Silverlight, modificar elementos de manera directa entre diferentes procesos. Pensemos que la interfaz vi- sual se está ejecutando en un hilo, como ya hemos podido comprobar, y la función, ahora, se ejecuta en otro hilo, por lo que estos dos hilos de ejecución no pueden al- terarse entre ellos. Para poder hacerlo, es necesario dejar que el manejador del hilo principal se encargue de hacer las actualizaciones correspondientes a los elementos que pertenezcan a su dominio o estén bajo él. this.Dispatcher.BeginInvoke((ThreadStart)delegate() { this.progressBar.Value = (double)valor; } ); El código le avisa, al manejador del hilo, que debe ejecutar la actualización de la barra de progreso. Para esto, utilizamos otro delegado para crear un método anónimo, el cual ejecutará la actualización del control cuando el hilo principal pueda procesarlo. 7. INTERCONEXIÓN 260 07_Silverlight.qxp 9/30/09 1:35 PM Page 260
  • 263.
    Hilos y eventos Podemosllegar aún más lejos con Silverlight y el uso de hilos de ejecución si im- plementamos eventos. Si bien ya estamos familiarizados con los eventos debido a que hemos hecho uso de ellos con la implementación de botones, listas des- plegables y otros controles con la capacidad de notificarnos el momento en que se produce un cambio interno en el control o cuando el usuario interactúa con él, también es posible crear estos eventos por nuestra cuenta. Esto puede ser es- pecialmente útil si lo conjugamos con el uso de hilos. De esta forma, podríamos iniciar un hilo de ejecución para una tarea y hacer que ésta, al finalizar o al su- ceder diferentes hitos, nos avise de estos hechos para que el código que hubiera iniciado el nuevo proceso sepa cómo reaccionar basado en estos cambios. Pode- mos declarar un evento de la siguiente forma: delegate void delegadoEvento(int valor); event delegadoEvento eventoHilo; Notemos que la primera línea es un delegado. Este delegado representa la firma que deberán tener aquellas funciones o métodos que quieran obtener alguna noti- ficación por parte del evento. En este caso, la función que implemente este even- to deberá recibir un valor entero como parámetro de entrada. La siguiente línea es el evento propiamente dicho, el cual hace uso de la firma provista por el delegado creado con anterioridad. Si extendemos el ejemplo utilizado para crear nuestros propios hilos, podríamos asociar la función de actualización de la barra de progre- so al evento para que, cuando el hilo ejecutado en paralelo ejecute cada iteración, nos notifique de los cambios realizados por medio del evento. private delegate void delegadoEvento(int valor); private event delegadoEvento eventoHilo; public Page() Manejo de hilos 261 RRR Si bien el concepto de delegados es mucho más complejo y profundo, para entenderlo de ma- nera rápida podemos decir que un delegado es el equivalente a un puntero o apuntador hacia una función o método. Este delegado es usado, en la mayoría de los casos, para llamar a la fun- ción apuntada desde otros métodos y procesos. DELEGADOS 07_Silverlight.qxp 9/30/09 1:35 PM Page 261
  • 264.
    { InitializeComponent(); eventoHilo += newdelegadoEvento(Page_eventoHilo); } void Page_eventoHilo(int valor) { this.Dispatcher.BeginInvoke((ThreadStart)delegate() { this.progressBar.Value = (double)valor; } ); } Veamos que concatenamos al evento un delegado que apunta a una función creada por nosotros y que contiene la actualización de la barra de progreso. Por último, la función que incluye la iteración es modificada para que dispare este evento. private void RealizarProceso() { for (int i = 0; i 100; i++) { eventoHilo(i); Thread.Sleep(500); } } Los eventos suelen ser una gran ayuda en implementaciones complejas. De cualquier manera, es necesario tener cuidado cuando trabajemos con eventos, ya que pueden arrojarnos un error si ninguna función o método se suscribió. Esto quiere decir que, mientras nadie se suscriba al evento, éste será nulo y, cuando intentemos ejecutarlo, ob- tendremos un error de referencia no inicializada. Para solucionar este problema, es re- comendable usar el código que aparece debajo. Así, podremos garantizar que si nadie se ha suscrito al evento, éste no se disparará y, por ende, no obtendremos un error. if (eventoHilo != null) { eventoHilo(i); } 7. INTERCONEXIÓN 262 07_Silverlight.qxp 9/30/09 1:35 PM Page 262
  • 265.
    Figura 22. Sino se asocia ninguna función al evento, éste genera un error al intentar ejecutarse. CONSUMIR SERVICIOS DESDE SILVERLIGHT Al principio de este capítulo hicimos uso del objeto WebClient para enviar infor- mación hacía una página web y tomar los resultados arrojados por ella. Pudimos crear un lector de RSS y también capturar datos desde la página sobre la base de los datos introducidos por el usuario en nuestra aplicación Silverlight. Si bien éste puede ser un buen mecanismo para enviar e interactuar con elementos que se encuentren fuera de nuestra aplicación web, no sirve para cubrir todos los casos posibles. Pensemos en modelos donde necesitemos agregar mayor seguridad al transporte de la información o en el que requiramos poder obtener información en forma de tipos de datos concretos y conocidos por nuestra aplicación. Para estos casos, es común la implementación de servicios web en los que un sitio, nuestro o de un tercero, expone en Internet métodos o funciones para procesar y devolver información. Otras aplicaciones pueden conectarse a estos servicios, consumir esa información y mostrarla en el ámbito de la misma aplicación, simu- lando que los datos desplegados fueran generados por ésta, sin tener que enviar al usuario a una página web distante. Así como podemos conectarnos a servicios distantes, también es posible consu- mir información de servicios creados por nosotros y que trabajen en nuestro si- tios web. Para esto, necesitamos contar con un sitio web; y para ello crearemos una aplicación Silverlight dejando que Visual Studio cree el sitio web utilizado para poder depurar y visualizar la aplicación Silverlight. Una vez que tengamos Consumir servicios desde Silverlight 263 07_Silverlight.qxp 9/30/09 1:35 PM Page 263
  • 266.
    nuestra solución creada,en el proyecto web adicionaremos un nuevo servicio web, como vemos en la figura que aparece a continuación. Figura 23. Debemos adicionar un nuevo servicio web a nuestra aplicación ASP.net. Si no hemos trabajado nunca con servicios web creados con Microsoft .Net, notare- mos que no existe diferencia alguna con un método o función tradicional del lengua- je que estemos acostumbrados a usar. De cualquier manera, este método es decorado con algunos atributos que especifican su alcance, como podemos ver a continuación: [WebService(Namespace = “http://tempuri.org/”)] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] public class MiServicioWeb : System.Web.Services.WebService { [WebMethod] public long Sumar(long valor1, long valor2) { return valor1 + valor2; } } El atributo decorativo [WebMethod] especifica que la función o método dentro del servicio web resulta accesible desde Internet o la Web. De esta forma, el método 7. INTERCONEXIÓN 264 07_Silverlight.qxp 9/30/09 1:35 PM Page 264
  • 267.
    queda expuesto alas distintas aplicaciones que quieran consumirlo. Para poder consumir un servicio web, primero necesitaremos saber dónde se encuentra, en la Web, ese servicio. Sin esta ruta, no podremos acceder a él. En el caso del servicio web creado previamente, si estamos trabajando de manera local, es posible ver su dirección al ejecutar el servicio. Por lo general, podremos encontrarlo con el apar- tado http://localhost que hace referencia a nuestro equipo. El siguiente paso es el de adicionar esta referencia al servicio dentro de nuestra aplicación Silverlight. Pa- ra esto, agregaremos una nueva referencia web apuntando al servicio en cuestión, como vemos en la siguiente figura. Figura 24. Agregando una referencia de un servicio web a nuestra aplicación Silverlight. Entre los protocolos de comunicación usados por los servicios web, se encuentra el llamado SOAP (Simple Object Access Protocol, o en castellano, protocolo de acceso a objetos simple). Este protocolo sirve para transportar objetos de forma simple en- tre aplicaciones. Además, se basa en XML para representar los distintos elementos que se transportarán y, si bien no es el objetivo de este libro profundizar en este pro- tocolo, sí es necesario mencionar que, en el caso de Silverlight, usaremos SOAP pa- ra transportar la información entre nuestra aplicación y el servicio web. Una vez Consumir servicios desde Silverlight 265 , El uso de Thread.Sleep() en los ejemplos es sólo para ilustrar un comportamiento de carga en la aplicación. Ya que Thread.Sleep() detiene momentáneamente la ejecución del hilo actual, el uso en aplicaciones finales podría causar un deterioro en la velocidad de ejecución de ésta. THREAD.SLEEP() 07_Silverlight.qxp 9/30/09 1:35 PM Page 265
  • 268.
    adicionada la referenciaal servicio web, podremos verla en el árbol del proyecto. El servicio creado tiene la finalidad de sumar dos números largos y retornarnos el resultado de la operación. Para esto, es necesario que primero enviemos estos nú- meros introducidos por el usuario. Crearemos una interfaz con un par de controles TextBox, un botón y algunas etiquetas para escribir en ellas. UserControl x:Class=”Capitulo7ServiciosWeb.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”400” Height=”300” xmlns:d=”http://schemas.microsoft.com/expression/blend/2008” xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006” mc:Ignorable=”d” Grid x:Name=”LayoutRoot” Background=”White” Button Click=”Button_Click” Margin=”167,30,190,0” VerticalAlignment=”Top” Content=”Sumar” d:LayoutOverrides=”Width”/ TextBox HorizontalAlignment=”Left” Margin=”8,28,0,0” VerticalAlignment=”Top” Width=”69” Text=”” TextWrapping=”Wrap” x:Name=”valor1”/ TextBox HorizontalAlignment=”Left” Margin=”94,28,0,0” VerticalAlignment=”Top” Width=”69” Text=”” TextWrapping=”Wrap” x:Name=”valor2”/ TextBlock x:Name=”resultado” HorizontalAlignment=”Left” Margin=”8,69,0,0” VerticalAlignment=”Top” Text=”Resultado:” TextWrapping=”Wrap” Width=”155”/ TextBlock HorizontalAlignment=”Left” Margin=”8,8,0,0” VerticalAlignment=”Top” Width=”177” Text=”Escriba los números a sumar:” TextWrapping=”Wrap”/ /Grid /UserControl 7. INTERCONEXIÓN 266 _` El canal del clima o Weather Channel, posee un servicio web para consulta del clima. Con este servicio, tendremos la capacidad de desplegar los datos climáticos de cualquier parte del mun- do en nuestra aplicación. Podemos registrarnos a este servicio de forma gratuita por medio de su sitio web en www.weather.com/services/xmloap.html. EL CANAL DEL CLIMA 07_Silverlight.qxp 9/30/09 1:35 PM Page 266
  • 269.
    El siguiente pasoconsiste en tomar los valores introducidos por el usuario, conec- tarse al servicio web y entregarle estos valores. private void Button_Click(object sender, RoutedEventArgs e) { ServicioSumar.MiServicioWebSoapClient servicio = new ServicioSumar.MiServicioWebSoapClient(); servicio.SumarCompleted += new EventHandlerServicioSumar.SumarCompletedEventArgs (servicio_SumarCompleted); servicio.SumarAsync(long.Parse(this.valor1.Text), long.Parse(this.valor2.Text)); } Como podemos ver, deberemos realizar tres pasos para poder trabajar con el servicio web. Primero, crearemos una instancia del servicio ya adicionado como referencia web a nuestro proyecto. Luego, enlazamos un método o función al evento Completed del método por ejecutar. Esto es debido a que necesitamos llamar de forma asíncrona al servicio web, y este evento nos avisará cuando la llamada se haya completado. Por úl- timo, ejecutamos el evento del servicio pasando los dos valores introducidos por el usuario. Una vez que el servicio haya realizado de manera correcta el proceso de su- ma, nos retornará el resultado para que podamos desplegarlo en nuestra aplicación. void servicio_SumarCompleted(object sender, ServicioSumar.SumarCompletedEventArgs e) { this.resultado.Text = “Resultado: “ + e.Result.ToString(); } Consumir servicios desde Silverlight 267 RRR Debido a que los datos transferidos por un servicio web son, típicamente, XML, puede resultar difícil probar el servicio sin tener que realizar código. Por esto, Microsoft .Net nos provee de una interfaz web para probar el servicio. Para acceder a ella, sólo tendremos que navegar hasta el servicio de forma local. PROBAR SERVICIOS WEB 07_Silverlight.qxp 9/30/09 1:35 PM Page 267
  • 270.
    7. INTERCONEXIÓN 268 El objetoe contiene los resultados devueltos por el servicio, por lo que tomamos de éste la respuesta enviada por el servicio llamado previamente. Figura 25. Al llamar al servicio enviándole los dos valores introducidos por el usuario, el servicio realiza el cálculo matemático y retorna el resultado. Si bien en el ejemplo hemos enviado y recibido tipos de datos primitivos, es posible también enviar y recibir tipos complejos, como entidades de datos, listas y colecciones de elementos, entre otros. Para entender esto, crearemos en el proyecto que contiene el servicio web una entidad para transportar datos de un usuario de la siguiente forma: public class Usuarios { public string Nombre { get; set; } public string Apellido { get; set; } public string Correo { get; set; } } Esta clase representará los datos de un usuario que trataremos de enviar a la aplica- ción Silverlight desde el servicio web. Para esto, tendremos que agregar un nuevo método web que retorne dicha entidad, como vemos a continuación: 07_Silverlight.qxp 9/30/09 1:35 PM Page 268
  • 271.
    [WebMethod] public Usuarios LeerUsuario() { returnnew Usuarios() { Nombre = “Usuario 1”, Apellido = “Apellido 1”, Correo = “Correo 1” }; } De la misma forma que hicimos en el primer ejemplo, deberemos conectarnos al servicio web, llamar al método que retorne el tipo complejo para luego poder manipularlo en la aplicación Silverlight. private void Button_Click_1(object sender, RoutedEventArgs e) { ServicioSumar.MiServicioWebSoapClient servicio = new ServicioSumar.MiServicioWebSoapClient(); servicio.LeerUsuarioCompleted += new EventHandlerServicioSumar.LeerUsuarioCompletedEventArgs (servicio_LeerUsuarioCompleted); servicio.LeerUsuarioAsync(); } void servicio_LeerUsuarioCompleted(object sender, ServicioSumar.LeerUsuarioCompletedEventArgs e) { ListServicioSumar.Usuarios usuarios = new ListServicioSumar.Usuarios(); usuarios.Add(e.Result); this.grilla.ItemsSource = usuarios; } Como el servicio expone el tipo complejo al devolverlo en el método LeerUsuario, este tipo puede ser usado desde la aplicación Silverlight para reconocer el valor re- tornado y así capturar los resultados. En la Figura 26, vemos el resultado de llamar al servicio web, leer el resultado y asignarlo a una grilla de datos. Consumir servicios desde Silverlight 269 07_Silverlight.qxp 9/30/09 1:35 PM Page 269
  • 272.
    Figura 26. Lagrilla muestra el registro enviado por el servicio web. Si hacemos uso de las últimas tecnologías propuestas por Microsoft, vale mencio- nar que Silverlight no sólo puede consumir información de servicios web clásicos, sino que también puede conectarse y consumir información de servicios WCF (Windows Communication Foundation). Esta tecnología permite inicializar y hos- pedar servicios sin la necesidad de contar con un servidor que contenga IIS (Internet Information Services) para administrar el servicio, como pasaría en el caso de los primeros servicios web creados en este capítulo. Crear un servicio WCF El primer paso para crear nuestro servicio WCF será agregar, al proyecto web creado junto con nuestra aplicación Silverlight, un servicio del tipo WCF para Silverlight. Lue- go, debemos seleccionar el tipo de servicio. En este caso, un servicio WCF preparado para ser consumido desde Silverlight. Este servicio, a diferencia del que ya hemos usa- do, posee dos atributos nuevos para identificar el servicio y los métodos expuestos: • ServiceContract: este contrato de servicio, distingue la clase que será expuesta co- mo un servicio. Esta clase puede contener diferentes métodos expuestos. • OperationContract: los contratos de operación representan cada uno de los méto- dos o funciones expuestos por el servicio y con los cuales se podrá interactuar. [ServiceContract(Namespace = “”)] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 7. INTERCONEXIÓN 270 07_Silverlight.qxp 9/30/09 1:35 PM Page 270
  • 273.
    public class ServicioWCF { [OperationContract] publicvoid EscribirMensaje(string mensaje) { ... } } La segunda parte hace referencia a la configuración y exposición del servicio. Esto se realiza dentro del archivo de configuración de la aplicación, por lo general, re- presentado con el nombre App.Config o en un ambiente web como Web.Config. system.serviceModel behaviors serviceBehaviors behavior name=”Capitulo7WCFService.Web.ServicioWCFBehavior” serviceMetadata httpGetEnabled=”true” / serviceDebug includeExceptionDetailInFaults=”false” / /behavior /serviceBehaviors /behaviors serviceHostingEnvironment aspNetCompatibilityEnabled=”true” / services service behaviorConfiguration=”Capitulo7WCFService.Web.ServicioWCFBehavior” name=”Capitulo7WCFService.Web.ServicioWCF” endpoint address=”” binding=”basicHttpBinding” contract=”Capitulo7WCFService.Web.ServicioWCF” / endpoint address=”mex” binding=”mexHttpBinding” contract=”IMetadataExchange” / /service /services /system.serviceModel Esta configuración define por completo el comportamiento que tendrá el servicio. Incluye información relacionada con el descubrimiento del servicio por otras apli- caciones y el detalle de las excepciones que éste arroja. Con el servicio configurado, sólo nos resta crear la implementación del contrato. Consumir servicios desde Silverlight 271 07_Silverlight.qxp 9/30/09 1:35 PM Page 271
  • 274.
    [ServiceContract(Namespace = “”)] [AspNetCompatibilityRequirements(RequirementsMode= AspNetCompatibilityRequirementsMode.Allowed)] public class ServicioWCF { [OperationContract] public void EscribirMensaje(string mensaje) { Debug.WriteLine(mensaje); return; } } En este caso, todos los mensajes que reciba el servicio serán escritos en la consola de depuración. De esta forma, comprobaremos que la conexión es exitosa y que los mensajes están siendo recibidos por el servicio. Podremos verificar previamente que el servicio se encuentra activo, ejecutando la aplicación web y accediendo a la ruta donde ese servicio se encuentra alojado, como podemos ver en la Figura 27. Figura 27. El servicio WCF funciona de manera correcta. De la misma forma en que adicionamos el servicio web a nuestra aplicación Silverlight, el servicio WCF debe ser referenciado y adicionado a nuestra aplicación, como po- demos ver en la Figura 28. El procedimiento es idéntico, y se puede seleccionar el servicio en cuestión sobre la base de la dirección donde está alojado. 7. INTERCONEXIÓN 272 07_Silverlight.qxp 9/30/09 1:35 PM Page 272
  • 275.
    Figura 28. Adicionandoel servicio WCF a la aplicación Silverlight. Una vez adicionado el servicio, notaremos que el archivo de configuración de la aplicación Silverlight ha sido modificado para especificar la forma en la que ésta se conectará al servicio WCF. Esta configuración resulta de igual importancia que la vista anteriormente, ya que ambas deben tener cierta concordancia para que tan- to la aplicación que consume el servicio como el servicio en sí se comuniquen de igual forma. Veamos el código necesario para esto: configuration system.serviceModel bindings basicHttpBinding binding name=”BasicHttpBinding_ServicioWCF” maxBufferSize=”2147483647” maxReceivedMessageSize=”2147483647” security mode=”None” / Consumir servicios desde Silverlight 273 RRR Un método anónimo es una pieza de código que no posee una firma (nombre de función) específi- ca. Todo el código generado para este método es apuntado por un delegado, el cual representará el punto de entrada para la ejecución de las líneas creadas dentro de ese método anónimo. MÉTODOS ANÓNIMOS 07_Silverlight.qxp 9/30/09 1:35 PM Page 273
  • 276.
    /binding /basicHttpBinding /bindings client endpoint address=”http://localhost:2113/ServicioWCF.svc” binding=”basicHttpBinding” bindingConfiguration=”BasicHttpBinding_ServicioWCF” contract=”ServicioWCF.ServicioWCF” name=”BasicHttpBinding_ServicioWCF” / /client /system.serviceModel /configuration Cuandoya tenemos todos los elementos configurados, sólo nos resta llamar al servicio pasándole los parámetros definidos por éste. Notaremos que la forma de hacerlo es idéntica a la que ya hemos usado. private void Button_Click(object sender, RoutedEventArgs e) { ServicioWCF.ServicioWCFClient servicio = new ServicioWCF.ServicioWCFClient(); servicio.EscribirMensajeCompleted += new EventHandlerSystem.ComponentModel.AsyncCompletedEventArgs(servicio_ EscribirMensajeCompleted); servicio.EscribirMensajeAsync(this.textoMensaje.Text); } void servicio_EscribirMensajeCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) { } Si ejecutamos nuestra aplicación Silverlight, podremos ver con claridad cómo los valores escritos en ésta son enviados al servicio para que, por último, sean escri- tos en la consola de depuración, como vemos en la siguiente imagen. 7. INTERCONEXIÓN 274 07_Silverlight.qxp 9/30/09 1:35 PM Page 274
  • 277.
    Figura 29. Mientrasse envían datos desde Silverlight, el servicio los escribe en la consola de depuración. De esta forma, hemos podido conectarnos tanto a servicios web tradicionales como al nuevo modelo de comunicación de Microsoft: Windows Communication Foundation. El acceso y manipulación de servicios puede sernos de extrema ayuda en los casos en que necesitemos extender la funcionalidad de Silverlight o inter- conectarlo con aplicaciones y lenguajes que no estén directamente relacionados a tecnologías Microsoft. Pensemos en la posibilidad de conectarnos a servicios creados en lenguajes, como PHP, Java o Ruby, que trabajen en ambientes no re- lacionados en forma directa con productos Microsoft, como Windows. MANIPULAR DATOS En el desarrollo de aplicaciones empresariales, uno de los puntos fuertes es la ma- nipulación de datos. Cómo capturar y mostrar información desde el usuario y hacia él, y almacenarla o recuperarla, son algunos de los retos con los que los desarrolla- dores se enfrentan a cada momento. Por esto, es necesario también poder contar con formas fáciles y rápidas de realizar estas tareas. Silverlight implementa varías téc- nicas y modelos que simplifican el desarrollo de aplicaciones orientadas a los datos. Por un lado, podemos usar el concepto de enlazado de datos, que hace referencia a que, sobre la base de los datos que tengamos disponibles y de su estructura, po- damos especificar qué controles y componentes los mostrarán y cómo lo harán, así como actualizar esta información de vuelta hacia los elementos que originalmente transportaban esta información. Otra de las posibilidades brindadas es el uso de Manipular datos 275 07_Silverlight.qxp 9/30/09 1:35 PM Page 275
  • 278.
    LinQ. Tras unamodificación al lenguaje de programación, se incluye este modelo que nos brinda la posibilidad de realizar consultas sobre objetos XML o bases de da- tos, pero desde el punto de vista de la programación orientada a objetos. Esto quie- re decir que, mediante el uso de sintaxis de programación orientada a objetos, es posible ejecutar consultas similares a las encontradas en las bases de datos, hacien- do que los distintos objetos creados por código puedan ser filtrados, ordenados y agrupados, entre otras posibilidades. Enlazado de datos Esta técnica, entonces, se refiere a la posibilidad de que los valores contenidos en una entidad contenedora de datos puedan ser leídos y mostrados de manera auto- mática. Decimos que es de forma automática ya que, en los casos más comunes, se suele leer el valor del origen de datos y asignarlo al elemento de la interfaz que queramos que muestre esta información. this.textBoxNombre.Text = persona.Nombre; this.textBoxApellido.Text = persona.Apellido; this.textBoxCorreo.Text = persona.Correo; Si bien las líneas de código vistas no representan un problema, con grandes volúme- nes de información pueden requerir mucho esfuerzo para su construcción. Además, pueden incurrir en costos de mantenimiento. Si agregáramos o modificáramos algu- na de las propiedades del objeto contenedor de datos, tendríamos que cambiar tam- bién nuestro código. Al mismo tiempo, si necesitáramos hacer que uno de los valores anteriores se mostrase en otra caja de texto y no en la predefinida en el código, sería necesario tener que modificar esas líneas y compilar la aplicación otra vez. Para solu- cionar este problema y asociar los datos a los distintos controles de nuestra interfaz, podemos utilizar el enlazado de datos en el código XAML, especificando el nombre de la propiedad del contenedor de datos del cual tomaremos la información: Text=”{Binding Correo}” Mediante el uso de la cláusula Binding, acompañada del nombre de la propiedad de la que se consumirá la información, la propiedad del control asociado toma- rá este valor y lo aplicará en tiempo de ejecución. Así, si necesitáramos modifi- car esta información (la fuente del dato), sólo deberíamos cambiar el código XAML sin necesidad de recompilar toda la aplicación. Veamos cómo podríamos aplicar esta forma de enlazado de datos en nuestra aplicación: 7. INTERCONEXIÓN 276 07_Silverlight.qxp 9/30/09 1:35 PM Page 276
  • 279.
    UserControl x:Class=”Capitulo7DataBinding.Page” xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” Width=”400” Height=”300” xmlns:d=”http://schemas.microsoft.com/expression/blend/2008” xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006” mc:Ignorable=”d” Gridx:Name=”LayoutRoot” Background=”White” Grid.RowDefinitions RowDefinition Height=”0.177*”/ RowDefinition Height=”0.187*”/ RowDefinition Height=”0.21*”/ RowDefinition Height=”0.427*”/ /Grid.RowDefinitions Grid.ColumnDefinitions ColumnDefinition Width=”0.315*”/ ColumnDefinition Width=”0.685*”/ /Grid.ColumnDefinitions TextBox Margin=”8,31,82,8” Grid.Column=”1” Grid.Row=”2” Text=”{Binding Correo}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBox Margin=”8,24,82,8” Grid.Column=”1” Grid.Row=”1” Text=”{Binding Apellido}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBox Margin=”8,21,82,8” Grid.Column=”1” Text=”{Binding Nombre}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ Button Click=”Button_Click” HorizontalAlignment=”Left” Margin=”8,0,0,8” VerticalAlignment=”Bottom” Grid.Column=”1” Grid.Row=”3” Content=”Leer” d:LayoutOverrides=”Height”/ Button Click=”Button_Click_1” HorizontalAlignment=”Left” Margin=”42,0,0,8” VerticalAlignment=”Bottom” Grid.Column=”1” Grid.Row=”3” Content=”Guardar”/ TextBlock Margin=”62.594,0,8.161,8” VerticalAlignment=”Bottom” Text=”Nombre:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBlock Margin=”62.594,0,8.161,8” VerticalAlignment=”Bottom” Grid.Row=”1” Text=”Apellido:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBlock HorizontalAlignment=”Right” Margin=”0,0,7.717,8” VerticalAlignment=”Bottom” Width=”55” Grid.Row=”2” Text=”Correo:” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ Manipular datos 277 07_Silverlight.qxp 9/30/09 1:35 PM Page 277
  • 280.
    /Grid /UserControl Notemos que aúnno hemos especificado la fuente de datos. Si bien los controles saben el nombre de la propiedad de la cual obtendrán la información por mostrar, ésta no ha sido especificada aún. Para lograr esto, podremos asignar el objeto con- tenedor de datos al control que incluye los controles que configuramos para que usen enlazado de datos. En este caso, el control Grid es el agrupador de los contro- les TextBox, y lo usaremos para asignar los datos. private Persona persona; public Page() { InitializeComponent(); persona = new Persona() { Nombre = “Persona 1”, Apellido = “Apellido 1”, Correo = “Correo 1” }; } private void Button_Click(object sender, RoutedEventArgs e) { this.LayoutRoot.DataContext = persona; } Si usamos la propiedad DataContext del control Grid, asignamos el objeto de datos y, como resultado de esta acción, todos los valores serán recolectados y desplega- dos por los correspondientes controles. 7. INTERCONEXIÓN 278 RRR Debido a que en un principio asignamos un tipo de dato específico, la propiedad DataContext retornará el mismo tipo de datos que hemos asignado, lo que nos ahorrará líneas de código al tener que transformar nuestros objetos a algún otro tipo específico, y viceversa. DATACONTEXT 07_Silverlight.qxp 9/30/09 1:35 PM Page 278
  • 281.
    Figura 30. Valoresasignados en forma automática mediante enlazado de datos. Así como asignamos valores mediante el atributo DataContext, es posible recolectar los cambios de estos valores por medio de la misma propiedad, como vemos en el código inferior. Si dejamos el enlazado de datos tal como lo definimos al principio, por más que el usuario realice cambios en los valores de la interfaz, al tratar de recolectar la in- formación, éstos valdrán exactamente lo mismo que en el momento de la asignación. persona = (Persona)this.LayoutRoot.DataContext; Figura 31. Los datos fueron actualizados en la interfaz, pero la propiedad DataContext retornó valores no actualizados. Manipular datos 279 07_Silverlight.qxp 9/30/09 1:35 PM Page 279
  • 282.
    Esto se debea que es posible especificar la forma en la que los controles con datos en- lazados se comportarán ante los cambios. Configuramos el enlace de datos con alguna de las siguientes propiedades basados en el comportamiento que queramos obtener: • OneWay: éste es el valor por defecto. Hará que el control enlazado modifique su valor sólo cuando la fuente de datos sea modificada. • TwoWay: actuará tanto cuando la fuente de datos sea modificada así como cuan- do el control sufra un cambio. De esta forma, si el usuario modificara el texto des- plegado en un control, este cambio se vería reflejado en la fuente de datos. • OneTime: sólo actualizará los controles la primera vez que se asignen los valores desde la fuente de datos. Luego, no se verán afectados por cambios en la fuente de datos y tampoco ejercerán cambios sobre ella. Si hacemos una modificación a nuestros controles enlazados, actualizaremos los valo- res de la fuente de datos sobre la base de las modificaciones realizadas por el usuario. TextBox Margin=”8,31,82,8” Grid.Column=”1” Grid.Row=”2” Text=”{Binding Correo, Mode=TwoWay}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBox Margin=”8,24,82,8” Grid.Column=”1” Grid.Row=”1” Text=”{Binding Apellido, Mode=TwoWay}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ TextBox Margin=”8,21,82,8” Grid.Column=”1” Text=”{Binding Nombre, Mode=TwoWay}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ Figura 32. En este caso, los datos fueron actualizados en la interfaz, y la propiedad DataContext retornó valores actualizados. 7. INTERCONEXIÓN 280 07_Silverlight.qxp 9/30/09 1:35 PM Page 280
  • 283.
    En el ejemploanterior hemos usado, como tipo de dato base para todos los valo- res, un string o texto, pero esto no siempre será de esta manera, ya que a veces se necesitan otro tipo de valores para albergar, por ejemplo, datos numéricos, fechas y demás. Si enlazáramos datos diferentes al de texto y el usuario introdujera un va- lor no soportado por ese tipo de datos, por ejemplo, un campo numérico para alo- jar el precio de un producto, y el usuario escribiera una letra, obtendríamos un error en la aplicación. Esto se debe a que, al tratar de pasar los valores de la inter- faz a la entidad asignada, los tipos de datos colapsarían. Para evitar esto, podemos hacer uso de validadores en el enlazado de datos que, si bien no prevendrán del error, sí nos avisarán para que nosotros tomemos un curso de acción para solucio- narlo. Tengamos en cuenta la siguiente entidad de datos: public class Persona { public string Nombre { get; set; } public string Apellido { get; set; } public string Correo { get; set; } public int Edad { get; set; } } Adicionamos el campo Edad, de tipo numérico. En este caso, si el usuario colocase un valor no numérico, produciría un error al no poder pasar ese valor a uno que só- lo acepta números. Lo primero que haremos es agregar un nuevo control TextBox para desplegar un valor numérico desde la fuente de datos. TextBox Margin=”8,25,82,80” Grid.Column=”1” Grid.Row=”3” Text=”{Binding Edad, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}” TextWrapping=”Wrap” d:LayoutOverrides=”Height”/ Veamos que, en la propiedad Text del control, dentro de la declaración del en- lazado de datos previamente usada, ahora hemos agregado dos nuevos atributos: Manipular datos 281 07_Silverlight.qxp 9/30/09 1:35 PM Page 281
  • 284.
    ValidatesOnExceptions, que harálas validaciones en relación con lo introducido por el usuario y el tipo de dato de la fuente de datos; y NotifyOnValidationError, que dispara- rá un evento para notificar que se ha producido un error de validación. Debido a que hemos asignado la fuente de datos al contenedor de estos controles, es necesario decla- rar y capturar el evento disparado por el validador desde este punto. Grid x:Name=”LayoutRoot” Background=”White” BindingValidationError=”LayoutRoot_BindingValidationError” Grid.RowDefinitions ... Notemos la presencia de BindingValidationError. Este evento es el que nos avisará en el momento que alguna validación falle. Gracias a esto, podremos avisar al usua- rio que existe un problema para que haga los cambios correpondientes. private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e) { this.mensajeError.Text = “Se encontró un error en los datos.”; this.mensajeError.Text += “ Valor: “ + ((System.Windows.Controls.TextBox)(((System.Windows.RoutedEventArgs) (e)).OriginalSource)).Text; } Figura 33. Error de validación capturado y mensaje enviado al usuario. 7. INTERCONEXIÓN 282 07_Silverlight.qxp 9/30/09 1:35 PM Page 282
  • 285.
    Manipular datos 283 LinQ LinQ esuna modificación a los lenguajes de programación basados en Microsoft .Net Framework 3.5, que permite realizar consultas sobre XML, objetos y bases de datos simulando la sintaxis de SQL transaccional con palabras reservadas y un enfoque orien- tado a objetos. Es destacable la presencia de LinQ en Silverlight ya que, por el peque- ño tamaño de la firma instalable en el navegador del cliente, sería válido asumir que sólo contendrá funcionalidad mínima y que no podría incluir este tipo de aditamen- tos. Contar con esta clase de herramientas que pueden maximizar la productividad en el desarrollo hace que, una vez más, Silverlight esté listo para aplicaciones de gran escala. Para ver la potencia de LinQ, asumamos que necesitamos ordenar una lista de ele- mentos en un vector. Si bien contamos con mecanismos propios de .Net Framework, podría existir la posibilidad de que tengamos que implementar nuestra propia forma de ordenamiento. Una de las más conocidas es el ordenamiento de burbuja. static void Ordenamiento_Burbuja(int[] array) { long maximo_derecho = array.Length - 1; do { long ultimo_cambio = 0; for (long i = 0; i maximo_derecho; i++) { if (array[i] array[i + 1]) { int temp = array[i]; array[i] = array[i + 1]; array[i + 1] = temp; ultimo_cambio = i; } } maximo_derecho = ultimo_cambio; } while (maximo_derecho 0); } La función antes planteada ordenará un vector de enteros, que tendrá como única tarea posible realizar este trabajo. Ahora veamos lo que podríamos lograr con LinQ: 07_Silverlight.qxp 9/30/09 1:35 PM Page 283
  • 286.
    int[] vector =new int[] { 10, 4, 5, 35, 23, 56 }; private void Button_Click(object sender, RoutedEventArgs e) { var q = from c in vector orderby c ascending select c; this.Ordenado.ItemsSource = q; } Si tenemos el mismo vector de números enteros, sólo ejecutamos una consulta sobre ese vector, ordenándolo de manera ascendente y asignándolo a un control ListBox. Co- mo podemos ver, para lograr el mismo resultado, la cantidad de código comparado con el ordenamiento por burbuja típico es sustancialmente menor y más fácil de entender. Figura 34. Un vector de enteros ordenado con LinQ. Pero LinQ puede ir mucho más lejos y no sólo ordenar vectores simples. Teniendo en cuenta que, a pesar de la reducción del volumen de código, la lógica para orde- nar el vector suele ser genérica, LinQ provee otras características sobre una colección de elementos o de objetos. Podríamos tener un tipo complejo como el que sigue: public class Estudiante { public enum Cursos 7. INTERCONEXIÓN 284 07_Silverlight.qxp 9/30/09 1:35 PM Page 284
  • 287.
    { A, B, C } public string Nombre {get; set; } public string Materia { get; set; } public Cursos Curso { get; set; } public string Ciudad { get; set; } public int Nota { get; set; } } Esta entidad posee diferentes elementos complejos como para invalidar el uso del ordenamiento por burbuja que habíamos visto inicialmente, sin tener que modi- ficarlo casi por completo. De cualquier manera, con LinQ podríamos solucionar este problema de forma sencilla. private void Button_Click_1(object sender, RoutedEventArgs e) { var q = from c in estudiantes where (c.Curso == Estudiante.Cursos.A) (c.Nota = 4) orderby c.Nota descending select c; this.grillaAlumnos.ItemsSource = q; } En este caso, de una lista de la entidad Estudiante, seleccionamos sólo los alumnos pertenecientes al curso A con una nota superior a 4, y ordenamos el resultado Manipular datos 285 07_Silverlight.qxp 9/30/09 1:35 PM Page 285
  • 288.
    basados en lanota de manera descendente. Como vemos en la siguiente figura, el resultado son los alumnos con el criterio de selección previamente formulado. Figura 35. Lista de estudiantes filtrada con LinQ. Podemos realizar tantas combinaciones en consultas como si se tratase de una consul- ta a una base de datos. A continuación, vemos cada una de las palabras reservadas que podemos usar para obtener información de nuestras colecciones de datos: • Where: condicionante basado en el predicado de la consulta. • Select/SelectMany: operador de proyección basado en el predicado de la consulta. Se- lecciona los elementos resultantes de la consulta como su pariente transaccional. • Take/Skip/TakeWhile/SkipWhile: operadores de partición basados en una posición o en el predicado de la consulta. • Join/GroupJoin: conjunción de dos o más elementos dentro de la consulta ba- sados en una llave común. • Concat: operador de concatenación. • OrderBy/ThenBy/OrderByDescending/ThenByDescending: operadores de ordena- miento, tanto ascendentes como descendentes. • Reverse: operador de ordenamiento que se encarga de revertir el orden de la se- cuencia original de la consulta. • GroupBy: agrupador de elementos basado en una llave de la consulta. • Distinct: operador que remueve los elementos duplicados de la consulta. • Union/Intersect: operadores que se ocupan de retornar la unión o la intersección de los elementos en la consulta. • Sum/Min/Max/Average: operadores utilizados para hacer cálculos matemáticos o de comportamiento dentro de la consulta. 7. INTERCONEXIÓN 286 07_Silverlight.qxp 9/30/09 1:35 PM Page 286
  • 289.
    Estos operadores puedenser aplicados a cualquier lista de objetos o a cualquier ele- mento que soporte la interfaz IEnumerable. Los resultados obtenidos con LinQ pueden ser moldeables. Con esto queremos decir que no es necesario que, tras cada consulta, retornemos un nuevo conjunto de elementos de la misma entidad filtrada. Es posible, con LinQ, retornar sólo los campos de la entidad que necesite- mos para ese momento, como podemos ver en el siguiente ejemplo: private void Button_Click_2(object sender, RoutedEventArgs e) { var q = from c in estudiantes where (c.Materia == “Matematica”) select new { c.Nombre, c.Materia }; this.grillaAlumnos.ItemsSource = q; } En el ejemplo anterior, el resultado sólo contendrá los nombres y las materias de los estudiantes que cumplan con el criterio de búsqueda, pero no se incluirán los de- más elementos de la entidad. LinQ tiene mucho potencial, por lo que no debere- mos desestimarlo en nuestros desarrollos. Si bien aquí sólo hemos visto la punta de lo que LinQ tiene para ofrecernos, a medida que lo pongamos en práctica recono- ceremos que podemos lograr cosas bastante complejas con muy poco código. Manipular datos 287 … RESUMEN Este capítulo nos ha terminado de mostrar la potencia de Silverlight cuando le agregamos có- digo C#. Hemos modificado el estado de los controles y componentes para que se comporten de distintas formas desde el código, aprendimos a guardar y a leer información del usuario, enviamos y recibimos información por medio de la red con un lector RSS, y utilizamos tecno- logías de conexión y transporte de datos para consumir información distante. Así, Silverlight orientado a animaciones y comportamiento visual se transforma en un Silverlight para el de- sarrollo de aplicaciones web de alto nivel. 07_Silverlight.qxp 9/30/09 1:35 PM Page 287
  • 290.
    288 PREGUNTAS TEÓRICAS 1 ¿Enqué casos deberemos usar el objeto WebClient? 2 ¿Qué evento del objeto WebClient debere- mos usar si queremos saber el progreso de la descarga del elemento por consumir desde nuestra aplicación Silverlight 2? 3 ¿Qué versión del lenguaje C# y de Microsoft .Net Framework podemos utilizar en las aplicaciones Silverlight 2? 4 ¿Qué es un HTTPHandler? 5 ¿Cuál es el concepto detrás del almacena- miento aislado? 6 ¿Cómo podemos adquirir mayor capacidad de almacenamiento dentro del área designa- da para cada usuario en el almacén aislado? 7 En el almacenamiento aislado, ¿sólo se pueden guardar archivos? 8 ¿Por qué no es posible modificar la interfaz gráfica de la aplicación Silverlight 2 desde un segundo hilo de ejecución? 9 ¿Es posible interactuar con tipos comple- jos retornados por servicios web desde Silverlight 2? 10¿Es posible en Silverlight 2 enlazar datos desde fuentes de datos de forma dinámica? ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Intente ampliar el ejemplo de utilización de LinQ, incorporando controles XAML con la lista de filtros y permitirle al usuario inte- ractuar con los datos y las búsquedas. 2 Para saber más sobre Windows Communi- cation Foundation, ingrese en http://msdn. microsoft.com y busque información. 3 Cree un modelo de objetos propio para almacenar información. Recolecte esa información ingresada por el usuario y envíela a un servicio web para que éste se encargue de almacenarla en una base de datos distante. 4 Haciendo uso de eventos e hilos de ejecu- ción, cree un temporizador personalizado. 5 Para saber más sobre el manejo de hilos de ejecución, ingrese en el sitio web oficial de MSDN: http://msdn.microsoft.com/es-es. 07_Silverlight.qxp 9/30/09 1:35 PM Page 288
  • 291.
    El navegador y sudominio Conectar tecnologías 290 Silverlight 2 y el HTML 290 HtmlDocument y HtmlElement 292 HtmlPage 300 HtmlWindow 305 Cookies 314 Modificar CSS 317 Silverlight 2 y JavaScript 320 Llamar funciones 323 Objetos Silverlight para JavaScript 324 Resumen 327 Actividades 328 Capítulo 8 El navegador web es el centro neurálgico de ejecución de Silverlight, que es hospedado por éste junto con otros lenguajes y tecnologías. JavaScript, HTML y ASP.net son algunos de los modelos que viven a través de nuestro navegador, y pueden ser conectados entre sí. En este capítulo haremos que Silverlight interactué con estas tecnologías comunes. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 08_Silverlight.qxp 9/30/09 1:36 PM Page 289
  • 292.
    CONECTAR TECNOLOGÍAS En elentorno del navegador web, trabajan diferentes tecnologías y lenguajes. Por ejemplo JavaScript, un lenguaje interpretado y ejecutado por el navegador que faci- lita desde la generación de contenido dinámico hasta validaciones de las entradas del usuario. Junto con JavaScript, podemos encontrar el lenguaje de etiquetas que da vi- da a la Web, el HTML, así como otras tecnologías tales como las hojas de estilo o el uso de XML. Todo esto es administrado por el navegador del usuario cada vez que éste accede y visualiza una página web. Por supuesto, Silverlight también es parte de este entorno, ya que trabaja dentro del navegador del cliente y convive con las tecno- logías antes mencionadas. El hecho de que Silverlight conviva con otras tecnologías web hace que sea natural encontrarse con la posibilidad de que este software pueda influir e interactuar con ellas, así como éstas podrían, también, modificar el compor- tamiento de la aplicación Silverlight creada y hospedada en este entorno común. Así es cómo Silverlight provee una serie de objetos que nos permiten interactuar con nues- tras páginas web, desde dentro de la aplicación Silverlight, y al mismo tiempo, su in- térprete, instalado en el navegador cliente y que hace uso del lenguaje JavaScript, per- mite crear y modificar aplicaciones Silverlight desde fuera de su contenedor. En este capítulo veremos, entonces, cómo es posible interactuar con Silverlight desde fuera de él y cómo éste, a su vez, puede modificar el ambiente que lo contiene. SILVERLIGHT 2 Y EL HTML Silverlight posee una serie de objetos, clases y componentes que nos permiten in- teractuar con el entorno donde está contenido. En este caso específico, con el HTML de la página web que contiene nuestra aplicación web. Si tenemos en cuen- ta que la aplicación Silverlight creada se declara en el código HTML por medio de tags que el navegador entienda, entonces la aplicación es un elemento más de to- do el conjunto de elementos que representan la página web. Si vemos el código HTML declarativo usado para incrustar aplicaciones Silverlight en HTML, nos daremos cuenta de que este elemento es uno más en el conjunto de tags. div id=”silverlightControlHost” object data=”data:application/x-silverlight-2,” type=”application/x- silverlight-2” width=”100%” height=”100%” param name=”source” value=”ClientBin/Capitulo8HTML.xap”/ param name=”onerror” value=”onSilverlightError” / param name=”background” value=”white” / 8. EL NAVEGADOR Y SU DOMINIO 290 08_Silverlight.qxp 9/30/09 1:36 PM Page 290
  • 293.
    param name=”minRuntimeVersion” value=”2.0.31005.0”/ param name=”autoUpgrade” value=”true” / a href=”http://go.microsoft.com/fwlink/?LinkID=124807” style=”text-decoration: none;” img src=”http://go.microsoft.com/fwlink/?LinkId=108181” alt=”Get Microsoft Silverlight” style=”border-style: none”/ /a /object iframe style=’visibility:hidden;height:0;width:0;border:0px’/iframe /div El código anterior nos muestra que, para que el navegador web pueda mostrar y eje- cutar la aplicación Silverlight, ésta debe ser declarada en el lenguaje que el navega- dor entienda, esto es, HTML, y, por consiguiente, será posible acceder a este HTML desde la aplicación Silverlight. A continuación, podemos ver la lista de clases y ob- jetos disponibles desde Silverlight para interactuar con nuestra página HTML. • HtmlPage: identifica la página HTML actual. Según dónde esté incrustado el control Silverlight, su contexto HTML es representado por este objeto. Este objeto provee las principales funcionalidades para interactuar con la página web actual, como cap- turar información del navegador en el que está corriendo la aplicación, abrir venta- nas emergentes, conocer configuraciones de seguridad del navegador, entre otras. • BrowserInformation: retorna información específica del navegador, como el tipo de navegador que se está usando, el nombre del navegador web, su versión, etcétera. • HtmlDocument: representa la página HTML, su estructura y tags. HtmlDocument puede ser útil en momentos en los que necesitemos modificar los elementos con- tenidos en nuestra página web. • HtmlElement: puede ser cualquier elemento HTML contenido en la página web. Se pueden usar métodos como SetAttribute() y SetProperty() para modificar cada elemento, pasando u obteniendo valores al elemento y desde él. • HtmlWindow: representa la ventana del navegador, proporcionando métodos para na- vegar a otras páginas o saltar entre diferentes marcadores dentro de la misma página. • HttpUtility: nos otorga un conjunto de herramientas de código para realizar tare- as sobre el HTML. Codificar y decodificar los parámetros enviados desde la pá- gina original hacia una página destino. • ScriptableTypeAttribute/ScriptableMemberAttribute: atributos que pueden ser aplica- dos a nuestras clases en Silverlight para hacerlas accesibles desde código JavaScript. • ScriptObject: referencia una función JavaScript escrita y ejecutada en la página web contenedora de la aplicación Silverlight. Esta referencia puede ser ejecutada desde nuestra aplicación Silverlight para realizar acciones fuera del contexto de Silverlight. Silverlight 2 y el HTML 291 08_Silverlight.qxp 9/30/09 1:36 PM Page 291
  • 294.
    HtmlDocument y HtmlElement ConHtmlDocument es posible modificar e interactuar con la estructura HTML pre- sente en el documento que albergue la aplicación Silverlight. El siguiente código lee la dirección web desde el navegador y la muestra dentro de nuestra aplicación Silverlight: private void Mostrarpagina_Click(object sender, RoutedEventArgs e) { HtmlDocument document = HtmlPage.Document; this.texto1.Text = document.DocumentUri.ToString(); } Como podemos observar en la Figura 1, la dirección URL donde se ubica la aplica- ción web es mostrada en un TextBox. Figura 1. Dirección URL donde se hospeda la aplicación Silverlight. HtmlDocument no sólo nos otorga algunos datos del navegador y la página web en la cual estemos ejecutando nuestra aplicación, también nos permite acceder a los elementos que estén fuera de nuestra aplicación. Veamos el siguiente código HTML: body style=”height: 100%; margin: 0;” form id=”form1” runat=”server” style=”height: 100%;” asp:ScriptManager ID=”ScriptManager1” runat=”server” /asp:ScriptManager div style=”height: 100%;” table 8. EL NAVEGADOR Y SU DOMINIO 292 08_Silverlight.qxp 9/30/09 1:36 PM Page 292
  • 295.
    tr td style=”width:500px; height:300px;” asp:SilverlightID=”Xaml1” runat=”server” Source=”~/ClientBin/Capitulo8HTML.xap” MinimumVersion=”2.0.31005.0” Width=”100%” Height=”100%” / /td /tr tr td input type=”text” id=”textBoxExterno” value=”” / /td /tr /table /div /form /body Como podemos observar en el código HTML que aparece más arriba, nuestra apli- cación Silverlight se encuentra dentro de una tabla HTML y, en el fondo de ella, un campo de texto declarado con tags HTML. Figura 2. La aplicación Silverlight dentro de una tabla HTML. Si nos basamos en la estructura anterior, donde hay un elemento HTML fuera de la aplicación, es posible que accedamos a ese elemento para modificar sus valores. Silverlight 2 y el HTML 293 08_Silverlight.qxp 9/30/09 1:36 PM Page 293
  • 296.
    private void Button_Click(objectsender, RoutedEventArgs e) { HtmlDocument documento = HtmlPage.Document; this.texto2.Text = documento.GetElementById(“textBoxExterno”).GetAttribute(“value”).ToString(); } Mediante el uso de GetElementById, palabra reservada homónima de JavaScript, accedemos al elemento creado por tags HTML en la página, haciendo uso del va- lor incluido en el atributo ID del componente. Luego, usando GetAttribute, refe- renciamos el atributo del elemento que contenga los valores por capturar. Como vemos en la figura siguiente, el contenido de la caja de texto HTML es pasado dentro de nuestra aplicación Silverlight. Figura 3. El valor de la caja de texto HTML es capturado por la aplicación Silverlight. Si hacemos uso de la misma técnica, podemos realizar la acción inversa: enviar información a cualquier elemento contenido dentro de la página web donde re- sida nuestra aplicación Silverlight. private void Button_Click_1(object sender, RoutedEventArgs e) { HtmlDocument documento = HtmlPage.Document; documento.GetElementById(“textBoxExterno”).SetAttribute(“value”, “Valor enviado desde Silverlight”); } 8. EL NAVEGADOR Y SU DOMINIO 294 08_Silverlight.qxp 9/30/09 1:36 PM Page 294
  • 297.
    En este caso,el texto utilizado en SetAttribute será alojado en la caja de texto HTML, fuera de la aplicación Silverlight. Figura 4. En este caso, la caja de texto HTML fue modificada desde Silverlight. Pero este tipo de atributos no sólo sirve para modificar o leer valores de los con- troles HTML de la página web. El comportamiento, por el contrario, es más cer- cano al que podría brindar JavaScript, ya que muchas propiedades no comunes en el tag HTML, pero que sí pueden ser accedidas desde JavaScript, también pueden ser accedidas y modificadas desde Silverlight. Agreguemos una fila más a la tabla HTML previamente creada. tr td div id=”constructorHTML” /div /td /tr Como vemos, hemos agregado una etiqueta div. Esta etiqueta tiene la particula- ridad de servir de contenedor de otras etiquetas HTML y, como tal, también es po- sible modificar su estructura HTML desde código JavaScript mediante el uso de la propiedad innerHTML. Entonces, podríamos hacer uso de innerHTML desde la apli- cación Silverlight para crear código HTML dentro de esta etiqueta. private void Button_Click_2(object sender, RoutedEventArgs e) Silverlight 2 y el HTML 295 08_Silverlight.qxp 9/30/09 1:36 PM Page 295
  • 298.
    { HtmlDocument documento =HtmlPage.Document; string constructor = “Introducir nombre: input type=”text” value=”” id=”nuevoTexto” style=”width:150px””; documento.GetElementById(“constructorHTML”).SetAttribute(“innerHTML”, constructor); } Como vemos en el código, construimos elementos HTML sobre la base de una ca- dena de texto que luego es asignado al atributo innerHTML del tag div, haciendo que este texto sea transformado en HTML. Figura 5. La nueva caja de texto, con un texto descriptivo creado desde Silverlight. Como este elemento es creado dentro del conjunto de elementos HTML que con- forman la página web, no sería impedimento, mediante el uso de GetAttribute y el identificador del nuevo control, para recuperar esta información una vez que el usua- rio hubiera completado el campo de texto. En caso de que tengamos que realizar una aplicación que no sólo trabaje con navega- dores de la gama de Internet Explorer, podemos hacer uso de otros mecanismos para crear controles de manera dinámica. Por ejemplo, mediante el uso de HtmlElement, ob- jetoquepermitelamanipulacióndeelementosindividualesdentrodelapáginaHTML. private void Button_Click_3(object sender, RoutedEventArgs e) { 8. EL NAVEGADOR Y SU DOMINIO 296 08_Silverlight.qxp 9/30/09 1:36 PM Page 296
  • 299.
    HtmlDocument documento =HtmlPage.Document; HtmlElement elemento = documento.CreateElement(“INPUT”); elemento.SetProperty(“type”, “text”); elemento.SetProperty(“value”, “Nuevo control”); documento.GetElementById(“constructorHTML”).AppendChild(elemento); } Veamos que, en el caso anterior, es necesario definir cada uno de los atributos que representarán el objeto HTML por crear. Inicialmente creamos un elemento de un tipo específico, un tipo INPUT, tag usado, por lo común, para definir elementos con los cuales el usuario pueda interactuar. El siguiente paso es definir el tipo de con- trol contemplado dentro de este tag y, por último, definimos un valor por defecto que se visualizará, al comienzo, cuando el control se cree en la página web. Por último, adicionamos este nuevo control a la lista de controles hijo del tag div con el que antes habíamos estado interactuando. Figura 6. Un nuevo control de texto creado mediante el uso de HtmlElement. De cualquier manera, no estamos sujetos a crear sólo elementos, como botones o cajas de texto, ya que es posible lograr cualquier elemento HTML representado por un tag. El siguiente código muestra cómo crear una imagen siguiendo el mismo pa- trón de creación de elementos HTML: private void Button_Click_4(object sender, RoutedEventArgs e) { Silverlight 2 y el HTML 297 08_Silverlight.qxp 9/30/09 1:36 PM Page 297
  • 300.
    HtmlDocument documento =HtmlPage.Document; HtmlElement elemento = documento.CreateElement(“IMG”); elemento.SetProperty(“src”, “http://static.redusers.com.ar/redusers/images/logo.jpg”); documento.GetElementById(“constructorHTML”).AppendChild(elemento); } Figura 7. Al presionar el botón en Silverlight, se crea una nueva imagen basada en los parámetros establecidos. Otra posibilidad que otorga el objeto HtmlDocument es la de enviar hacia el servi- dor toda la información contenida dentro de las etiquetas form de la página web. Por lo general, usamos estas etiquetas para enmarcar todos los controles web cuyo contenido será enviado al servidor para que luego éste capture la información in- troducida por el usuario. Para entender esto, veamos el siguiente código HTML: form id=”form1” runat=”server” style=”height: 100%;” asp:ScriptManager ID=”ScriptManager1” runat=”server” /asp:ScriptManager div style=”height: 100%;” ... ... /div /form 8. EL NAVEGADOR Y SU DOMINIO 298 08_Silverlight.qxp 9/30/09 1:36 PM Page 298
  • 301.
    Todos los elementoscontenidos dentro de las etiquetas form son capturados por la página y enviados al servidor para su procesamiento. Así, un usuario que hubie- se interactuado con cajas de texto, listas desplegables y otros controles podría no- tificar de estos cambios al código que se ejecuta en el servidor. En el caso de ASP.net, es posible analizar estos elementos desde el código creado en el servidor. Ese código podría ser como el que sigue: script runat=”server” protected void Page_Load(object sender, EventArgs e) { } /script En el momento en el que el formulario sea enviado desde el cliente al servidor, este método ASP.net se disparará y, si bien el usuario deberá realizar la acción de enviar esta información, también es posible hacerlo desde Silverlight. private void Button_Click_5(object sender, RoutedEventArgs e) { HtmlDocument documento = HtmlPage.Document; documento.Submit(); } Al ejecutar la línea documento.Submit(), el formulario se enviará al servidor como ve- mos en la Figura 8 y en la Figura 9, donde el campo de texto, al final de la aplicación Silverlight, contiene cierta información introducida por el usuario. Esta información, luego, es enviada y capturada por el código ASP.net. Silverlight 2 y el HTML 299 , La propiedad innerHTML sólo es válida en navegadores compatibles con Internet Explorer, debido a que Microsoft agregó esta funcionalidad al conjunto de sentencias disponibles para JavaScript bajo Internet Explorer. Si usamos innerHTML para nuestros desarrollos, podríamos obtener un error en tiempo de ejecución si el usuario utilizase un navegador no compatible. INNERHTML 08_Silverlight.qxp 9/30/09 1:36 PM Page 299
  • 302.
    Figura 8. Cajade texto modificada por el usuario. Figura 9. El valor de la caja de texto es capturado en el servidor una vez que se envía la información desde la aplicación Silverlight. HtmlPage El objeto HtmlPage también provee una serie de métodos y funciones para interactuar sobre la página web donde Silverlight reside. Si bien hemos utilizado este objeto para obtener una referencia al documento que representa el HTML de la página, HtmlPage se encuentra en un nivel superior y representa toda la información de la página en sí, pudiendo generar comportamientos en el navegador. Uno de ellos está ligado a la creación de ventanas emergentes. Las ventanas emergentes son aquellas que, al ingre- sar en un sitio o por medio de alguna acción del usuario, son disparadas en una nueva instancia del navegador web, apareciendo una segunda ventana que nos redirige a otra 8. EL NAVEGADOR Y SU DOMINIO 300 08_Silverlight.qxp 9/30/09 1:36 PM Page 300
  • 303.
    página. Con eluso de HtmlPage, es posible generar este comportamiento. La creación de una ventana emergente posee características similares a las presentadas en el código JavaScript. Veamos el siguiente código para entender mejor lo que queremos lograr. script language=”javascript” type=”text/javascript” function AbrirVentana() { var opciones = “width=300; height=300;”; window.open(“http://www.redusers.com”, “nuevaVentana”, opciones); } /script Notaremos que para crear una nueva ventana es necesario, como primer parámetro, definir la dirección web a la cual navegará esa ventana, un nombre que la identifique y una serie de parámetros que definirán su comportamiento. Como resultado, obten- dremos una nueva instancia del navegador, como vemos en la siguiente figura: Figura 10. Una ventana emergente desde JavaScript. Si entendemos este concepto, veremos que la forma de realizar esto desde Silverlight es similar. Veamos el código: HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions(); opciones.Width = 300; Silverlight 2 y el HTML 301 08_Silverlight.qxp 9/30/09 1:36 PM Page 301
  • 304.
    opciones.Height = 300; HtmlPage.PopupWindow(newUri(“http://www.redusers.com”), “_blank”, opciones); El resultado de este código será idéntico al obtenido con JavaScript, donde tam- bién deberemos definir una dirección URL, el nombre de la nueva instancia y una serie de opciones para configurar la ventana emergente. Las opciones de configu- ración de la ventana emergente pueden ser importantes a la hora de obtener un comportamiento visual específico. Podemos ver la lista de opciones dentro del ob- jeto HtmlPopupWindowOptions a continuación: • Height: determina el alto de la ventana en pixeles. • Width: determina el ancho de la ventana en pixeles. • Top: establece la posición, en pixeles, de la ventana emergente a partir del borde superior de la pantalla. • Left: establece la posición, en pixeles, de la ventana emergente a partir del bor- de izquierdo de la pantalla. • Directories: esta opción muestra u oculta los marcadores o vínculos del nave- gador para la ventana emergente. • Location: muestra u oculta la barra de navegación para la ventana emergente. • Menubar: muestra u oculta las opciones del navegador (menús). • Resizeable: permite la capacidad de que el usuario pueda cambiar, o no, de tama- ño la ventana emergente una vez creada. • Scrollbars: esta opción muestra u oculta las barras de desplazamiento, tanto ho- rizontales como verticales. • Status: muestra u oculta la barra de estado del navegador. • Toolbar: esta opción muestra u oculta la barra de herramientas del navegador en la ventana emergente. Aplicamos los atributos anteriores como en el siguiente código: HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions(); opciones.Directories = false; opciones.Height = 300; opciones.Left = 10; opciones.Location = false; opciones.Menubar = false; opciones.Resizeable = false; opciones.Scrollbars = false; 8. EL NAVEGADOR Y SU DOMINIO 302 08_Silverlight.qxp 9/30/09 1:36 PM Page 302
  • 305.
    opciones.Status = false; opciones.Toolbar= false; opciones.Top = 50; opciones.Width = 300; HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”, opciones); Figura 11. La posición y las propiedades configuradas en una nueva ventana. Debido a que las ventanas emergentes suelen ser intrusivas, o no necesariamente acep- tadas por todos los usuarios, los navegadores actuales cuentan con mecanismos para bloquear estas ventanas, haciendo que no puedan abrirse a menos que el usuario espe- cifique lo contrario. Debido a esto, si ejecutamos el código en forma directa y el nave- gador del cliente cuenta con una herramienta de bloqueo de ventanas emergentes, no podremos lanzar esta ventana y, por consiguiente, la funcionalidad que pudiéramos haber querido implementar se vería frenada. Para asegurarnos de que esto no pase, o por lo menos poder avisarle al usuario que necesitará realizar una acción específica pa- ra permitir las ventanas emergentes, es posible hacer uso del siguiente código: if (HtmlPage.IsPopupWindowAllowed) { HtmlPopupWindowOptions opciones = new HtmlPopupWindowOptions(); ... ... HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”, opciones); } Silverlight 2 y el HTML 303 08_Silverlight.qxp 9/30/09 1:36 PM Page 303
  • 306.
    else { this.mensaje.Text = “Nose permiten ventanas emergentes.”; } La propiedad IsPopupWindowAllowed nos permitirá saber si el navegador web del cliente tiene activado el bloqueo de ventanas emergentes pudiendo, como en el ejem- plo de la figura siguiente, avisarle al usuario de este impedimento. Figura 12. Así se muestra al usuario un mensaje sobre el bloqueo de ventanas emergentes. Cabe mencionar que además de abrir una ventana emergente dentro de su parámetro de retorno, HtmlPage.PopupWindow devuelve una referencia del tipo HtmlWindow. Con esta referencia, es posible modificar el comportamiento de la ventana antes abier- ta de la misma forma que lo haríamos desde código JavaScript. En el siguiente código de ejemplo, una vez creada la nueva ventana emergente, si el usuario pre- siona sobre el segundo botón de la aplicación Silverlight, redirigiremos el conte- nido de la ventana a otro sitio web. HtmlWindow window; private void Button_Click(object sender, RoutedEventArgs e) { if (HtmlPage.IsPopupWindowAllowed) { 8. EL NAVEGADOR Y SU DOMINIO 304 08_Silverlight.qxp 9/30/09 1:36 PM Page 304
  • 307.
    HtmlPopupWindowOptions opciones =new HtmlPopupWindowOptions(); ... ... ... window = HtmlPage.PopupWindow(new Uri(“http://www.redusers.com”), “_blank”, opciones); } else { this.mensaje.Text = “No se permiten ventanas emergentes.”; } } private void Button_Click_1(object sender, RoutedEventArgs e) { window.Navigate(new Uri(“http://www.bing.com”)); } Figura 13. Una vez creada la ventana, con el segundo botón la página es redirigida a un nuevo sitio web. HtmlWindow Para extender lo explicado en el apartado anterior, diremos que HtmlWindow re- presenta una referencia a una ventana del navegador. Ésta puede ser una ventana emergente o la misma ventana principal donde se ejecuta la aplicación Silverlight. Además de poder redirigir la página a un nuevo destino, HtmlWindow nos otorga algunos elementos más con los cuales trabajar. Silverlight 2 y el HTML 305 08_Silverlight.qxp 9/30/09 1:36 PM Page 305
  • 308.
    Por ejemplo, podríamosnecesitar requerir información por parte del usuario usando ventanas específicas del navegador y no creando las nuestras dentro de la aplicación Silverlight. La ventaja de realizar esto reside en que esos cuadros de diálogo pueden bloquear el uso de la página hasta que el usuario lo cierre. Al bloquear la interacción con la página, podemos asegurarnos de que el usuario siga el flujo de nuestra aplica- ción y no evada ciertas reglas necesarias en nuestro código. El siguiente código otor- ga la posibilidad de enviar una alerta al usuario en forma de cuadro de diálogo. private void Button_Click_2(object sender, RoutedEventArgs e) { HtmlWindow ventanaPrincipal = HtmlPage.Window; ventanaPrincipal.Alert(“Esta es una alerta desde Silverlight”); } Primero, tomamos la instancia de la ventana del navegador y, luego, mediante el uso de Alert() (homónimo de JavaScript), disparamos un mensaje al usuario. Figura 14. Mensaje de alerta desde Silverlight. Si intentamos acceder a cualquier elemento de la página web o de la aplicación Silverlight mientras que esta ventana se encuentre activa, notaremos que no es posible hacerlo, por lo que la única alternativa o curso de acción consiste en pre- sionar dicho elemento. Es posible extender los mensajes de alerta para pedirle al usuario confirmaciones sobre ciertas acciones. Por ejemplo, podríamos desplegar un cuadro de diálogo con dos opciones para que el usuario eligiese y, basados en su elección, actuar como corresponda. Figura 15. Cuadro de diálogo con dos opciones seleccionables. private void Button_Click_3(object sender, RoutedEventArgs e) { 8. EL NAVEGADOR Y SU DOMINIO 306 08_Silverlight.qxp 9/30/09 1:36 PM Page 306
  • 309.
    HtmlWindow ventanaPrincipal =HtmlPage.Window; if (ventanaPrincipal.Confirm(“¿Está seguro de seguir adelante?”)) { this.mensaje.Text = “Usted presionó SI”; } else { this.mensaje.Text = “Usted presionó NO”; } } Si hacemos uso del método Confirm(), podremos mostrar un cuadro de diálogo con dos opciones seleccionables por parte del usuario, que éste podrá aceptar o cancelar. Si la respuesta por parte del usuario fuera positiva, Confirm() retornará True (verdadero) y si no, False (falso). En la Figura 16, se muestran los dos cursos de acción sobre la base de la selección del usuario. Figura 16. A la izquierda, el usuario presionó el botón Aceptar y a la derecha el usuario presionó el botón Cancelar. Podemos ir todavía un paso más allá y realizar preguntas específicas al usuario, dejando que éste responda con libertad, introduciendo su respuesta en una caja de texto del mismo diálogo. Lo hacemos de la siguiente manera: private void Button_Click_4(object sender, RoutedEventArgs e) { Silverlight 2 y el HTML 307 08_Silverlight.qxp 9/30/09 1:36 PM Page 307
  • 310.
    HtmlWindow ventanaPrincipal =HtmlPage.Window; this.mensaje.Text = ventanaPrincipal.Prompt(“¿Le gusta Silverlight?”); } En este caso, el cuadro de diálogo se mostrará con el mensaje contenido dentro del método Prompt() y retornará un tipo de dato de texto que contiene la respuesta del usuario. En la Figura 17, podemos ver el mensaje que se muestra al usuario, donde podrá escribir la respuesta, y en la Figura 18 observamos que la respuesta es escrita dentro de la aplicación Silverlight. Figura 17. Cuadro de diálogo con una pregunta enviada al cliente. Figura 18. Lo escrito por el usuario es reflejado en la aplicación Silverlight. En este mismo capítulo pudimos abrir una nueva ventana emergente haciendo uso de PopupWindow(), pero también es posible que redirijamos la página web actual hacia otro destino web sin la necesidad de abrir una ventana nueva que pueda ser bloqueada por el navegador. private void Button_Click_5(object sender, RoutedEventArgs e) { HtmlWindow ventanaPrincipal = HtmlPage.Window; 8. EL NAVEGADOR Y SU DOMINIO 308 08_Silverlight.qxp 9/30/09 1:36 PM Page 308
  • 311.
    ventanaPrincipal.Navigate(new Uri(“http://www.bing.com”)); } En estecaso, estableciendo la página de navegación, en el momento que el usuario pre- sione el botón de la aplicación Silverlight, el navegador se dirigirá a la nueva página. Figura 19. A la izquierda, la aplicación Silverlight. A la derecha, el mismo navegador una vez que el usuario presionó el botón de navegación. Si fuera necesario, en lugar de lanzar la navegación en la página actual donde re- side la aplicación Silverlight, podríamos abrir una nueva página, similar a la ge- nerada por PopupWindow(), pero sin que el navegador bloquee dicha ventana, ya que ésta no tendría las mismas cualidades. Por ejemplo, no podríamos modificar los valores de la ventana emergente como el caso de PopupWindow().Utilizando el atributo _blank, la ventana se visualizará en una nueva ventana. private void Button_Click_5(object sender, RoutedEventArgs e) Silverlight 2 y el HTML 309 RRR El texto de los botones del cuadro de diálogo Confirm() dependerá directamente del idioma del navegador web que esté usando el usuario, así como también de su versión y su tipo. No se pue- de, en ningún caso, modificar por código estos valores. TEXTO EN BOTONES 08_Silverlight.qxp 9/30/09 1:36 PM Page 309
  • 312.
    { HtmlWindow ventanaPrincipal =HtmlPage.Window; ventanaPrincipal.Navigate(new Uri(“http://www.bing.com”), “_blank”); } También podemos, con HtmlWindow, navegar entre marcadores HTML. Los marcadores HTML son definidos por el tag a y una propiedad que identifi- que el nombre de este marcador. a name=”MiMarcador” Esto permitirá que, en la barra de navegación del navegador web, si especificamos este marcador, la página nos muestre esa zona. asp:ScriptManager ID=”ScriptManager1” runat=”server”/asp:ScriptManager div style=”height:100%;” asp:Silverlight ID=”Xaml1” runat=”server” Source=”~/ClientBin/Capitulo8HTML3.xap” MinimumVersion=”2.0.31005.0” Width=”100%” Height=”100%” / /div br / ... ... br / a name=”MiMarcador”/a br / Marcador HTML Vemos, en el código anterior, que el marcador se encuentra al final de la página HTML y nuestra aplicación Silverlight, en la parte superior. Desde Silverlight, po- dremos navegar hasta ese marcador de la siguiente forma: private void Button_Click_1(object sender, RoutedEventArgs e) { HtmlWindow paginaPrincipal = HtmlPage.Window; paginaPrincipal.NavigateToBookmark(“MiMarcador”); } 8. EL NAVEGADOR Y SU DOMINIO 310 08_Silverlight.qxp 9/30/09 1:36 PM Page 310
  • 313.
    Notemos la concordanciaentre el nombre del marcador HTML y el nombre utiliza- do en la línea de código Silverlight. Podemos ver el resultado en la siguiente figura. Figura 20. La página muestra el marcador HTML disparado desde Silverlight. Podemos extender este ejemplo simple para lograr que, sobre la base de los marcado- res, podamos cargar diferentes controles Silverlight contenidos en nuestra aplicación. Al hacer esto, podemos dar mayor facilidad de uso sobre la aplicación. Pensemos en una aplicación que tenga diferentes estados o páginas internas que se vayan mostran- do durante la interacción con el usuario. El usuario podría querer marcar una página específica de la aplicación para luego acceder directamente a esa parte de la aplicación. Sin embargo, debido a que cada vez que se carga la aplicación esto se hará desde el inicio, será difícil saber qué par- te es la que quiere ver el usuario. Pero, aplicando marcadores a la aplicación, es po- sible conseguir esto. Nuestro primer paso será agregar un nuevo control Silverlight a la solución. El siguiente paso será modificar el código que inicia la aplicación Sil- verlight (App.xaml.cs) de la siguiente forma: private Grid controlPrincipal = new Grid(); private void Application_Startup(object sender, StartupEventArgs e) { this.RootVisual = controlPrincipal; if (String.IsNullOrEmpty(HtmlPage.Window.CurrentBookmark)) { controlPrincipal.Children.Add(new Page()); } Silverlight 2 y el HTML 311 08_Silverlight.qxp 9/30/09 1:36 PM Page 311
  • 314.
    else { try { Type type =this.GetType(); Assembly assembly = type.Assembly; UserControl controlDestino = (UserControl)assembly.CreateInstance( HtmlPage.Window.CurrentBookmark); controlPrincipal.Children.Add(controlDestino); } catch { controlPrincipal.Children.Add(new Page()); } } } public static void Navegar(UserControl controlDestino) { HtmlPage.Window.NavigateToBookmark(controlDestino.GetType().FullName); } El código utiliza mecanismos de reflexión sobre los componentes para determinar qué control instanciar, basándose en el nombre contenido en el marcador del navegador web. Las siguientes líneas reconocen este nombre, buscan el control que corresponda, generando una instancia, y sobrescriben el aspecto visual original del control. Assembly assembly = type.Assembly; UserControl controlDestino = (UserControl)assembly.CreateInstance( HtmlPage.Window.CurrentBookmark); controlPrincipal.Children.Add(controlDestino); Además, hemos agregado un método estático que se encargará de hacer navegar la página web al marcador designado, utilizando como nombre del marcador el nombre de instancia del control. Esto nos permitirá realizar el siguiente código desde cualquier otro control Silverlight en el proyecto. 8. EL NAVEGADOR Y SU DOMINIO 312 08_Silverlight.qxp 9/30/09 1:36 PM Page 312
  • 315.
    private void Button_Click(objectsender, RoutedEventArgs e) { App.Navegar(new Pagina2()); } En la Figura 21 y en la Figura 22, podemos ver ejemplos con el resultado de aplicar este comportamiento a un proyecto. Figura 21. La aplicación navegó hasta el segundo marcador, mostrando un contenido nuevo. Figura 22. Al presionar sobre el botón contenido en el control anterior, éste navegará a la página principal. Silverlight 2 y el HTML 313 08_Silverlight.qxp 9/30/09 1:36 PM Page 313
  • 316.
    Prestemos atención almarcador que se genera por la aplicación Silverlight. La primera parte antes del punto hace referencia al nombre del ensamblado. Este nombre podemos obtenerlo desde las propiedades del proyecto. #Capitulo8HTML3.Pagina2 La segunda parte, después del punto, se refiere al nombre del control de usuario o clase que manejará ese control. Deberemos tener en cuenta esto para poder gene- rar, de manera correcta, la instancia del control que se va a visualizar. Figura 23. Propiedades del proyecto Silverlight, donde encontramos el nombre del ensamblado. Cookies Las cookies son archivos de texto que se alojan en el equipo del cliente. Casi siem- pre, son usados para dejar información del usuario para luego reutilizarla según la necesidad. Los casos más comunes de uso de cookies los podemos encontrar en aque- llos sitios web en los que, al ingresar, nos preguntan si deseamos que nos recuerden, por ejemplo, nuestro nombre de usuario y contraseña para validar nuestra entidad, para que no debamos volver a colocarlos la próxima vez que ingresemos. Estos sitios dejan un archivo de texto con valores y fecha de expiración en nuestra computado- ra, que leerán posteriormente para así recuperar eso que habían almacenado. Desde una aplicación Silverlight es posible, también, leer cookies que hayan sido cre- adas por el sitio web donde ésta trabaja o crear estos elementos para el mismo sitio web. No debemos comparar las cookies con la característica de almacenamiento aislado provista por Silverlight. Si bien la capacidad de las cookies para almacenar información 8. EL NAVEGADOR Y SU DOMINIO 314 08_Silverlight.qxp 9/30/09 1:36 PM Page 314
  • 317.
    es limitada, estoselementos se guardan en el equipo del cliente y pueden ser compar- tidos con otros ambientes de desarrollo. Estas cookies podrían ser manipuladas desde una aplicación ASP.net, como por JavaScript. Por este motivo, las cookies pueden con- vertirse en un buen canal de comunicación entre las distintas plataformas. En el siguiente ejemplo, crearemos una cookie desde ASP.net, que leeremos y mo- dificaremos desde Silverlight. Lo primero será crear la estructura y el código ASP.net. asp:Button ID=”Button1” runat=”server” Text=”Crear Cookie” onclick=”Button1_Click” / nbsp;asp:Button ID=”Button2” runat=”server” Text=”Ver Cookie” onclick=”Button2_Click” / br / asp:Label ID=”mensaje” runat=”server” Text=”Valor del Cookie:” Font- Names=”Arial”/asp:Label Aquí creamos dos botones, uno para crear la cookie y el otro para leerla. Los valores serán desplegados en el campo de texto que se encuentra declarado al final de las lí- neas anteriores. Para crear cookies desde ASP.net, escribiremos el siguiente código: protected void Button1_Click(object sender, EventArgs e) { Response.Cookies.Add(new HttpCookie(“CookieSilver”, “1234”)); } protected void Button2_Click(object sender, EventArgs e) { this.mensaje.Text = “Valor del Cookie: “ + Request.Cookies[“CookieSilver”].Value.ToString(); } El primer método crea una cookie llamada CookieSilver, que contiene el valor 1234. El segundo método lee y escribe el contenido de la cookie en el campo de texto. Una vez terminado este paso, podremos tomar esta cookie desde Silverlight. En el evento de presionado del botón, agregaremos el código de lectura y recolección de la cookie. private void Button_Click(object sender, RoutedEventArgs e) { string[] cookies = HtmlPage.Document.Cookies.Split(‘;’); Silverlight 2 y el HTML 315 08_Silverlight.qxp 9/30/09 1:36 PM Page 315
  • 318.
    foreach (string cookiein cookies) { string[] valores = cookie.Split(‘=’); if (valores.Length == 2) { if (valores[0].ToString() == “CookieSilver”) { this.mensaje.Text = “Valor del Cookie: “ + valores[1]; break; } } } } Hemos recolectado toda la información de las cookies disponibles mediante la línea: string[] cookies = HtmlPage.Document.Cookies.Split(‘;’); Debido a que podría haber más de una cookie, cada una de éstas se separarán me- diante el identificador de ; (punto y coma). Además, las cookies serán almacena- das con la estructura [Nombre]=[Valor], por lo que, delante del signo igual en- contraremos el nombre de la cookie y seguido, el valor almacenado. Al ejecutar el código, obtendremos algo similar a lo siguiente. Figura 24. La cookie fue recolectada por la aplicación Silverlight. 8. EL NAVEGADOR Y SU DOMINIO 316 08_Silverlight.qxp 9/30/09 1:36 PM Page 316
  • 319.
    Por supuesto, tambiénes posible crear o sobrescribir una cookie ya existente desde una aplicación Silverlight. Para esto, es necesario utilizar un modelo diferente que no incluye el uso de HtmlPage.Document.Cookies. En este caso, usaremos SetProperty, modificando el valor de la propiedad cookie del navegador. private void Button_Click_1(object sender, RoutedEventArgs e) { DateTime fechaExspiracion = DateTime.Now + TimeSpan.FromDays(7); string nuevoCookie = “CookieSilver=Nuevo Valor;expires=” + fechaExspiracion.ToString(“R”); HtmlPage.Document.SetProperty(“cookie”, nuevoCookie); } Notemos que, además del valor de la cookie, también es posible especificar una fecha de expiración. Esto quiere decir que, si agregamos una fecha a la cookie, ésta se mantendrá disponible hasta esa fecha. En caso de no especificar una fecha, la cookie se eliminará en el momento en el que abandonemos la página que la creó. En la Figura 25, podemos observar que el valor de la cookie modificada des- de la aplicación Silverlight también es reconocido desde ASP.net. Figura 25. La nueva cookie es reconocida por ASP.net. Modificar CSS Las hojas de estilo, también conocidas como CSS, pueden ser alteradas desde la aplicación Silverlight. Debido a que tenemos acceso al modelo de objetos de la Silverlight 2 y el HTML 317 08_Silverlight.qxp 9/30/09 1:36 PM Page 317
  • 320.
    página HTML, cualquierelemento presente en ésta podría ser cambiado desde nuestra aplicación. En el caso del uso de estilos, puede resultar de utilidad cuan- do necesitemos informar al usuario de algún acontecimiento modificando la ti- pografía o los colores del elemento. A continuación, veamos dos estilos creados en la página donde se ejecutará nuestra aplicación: style type=”text/css” .estilo1 { font-family: Arial; font-size: larger; color: Blue; } .estilo2 { font-family: Verdana; font-size: smaller; color: Green; } /style Estos estilos presentan una tipografía específica para cada uno, así como un tama- ño de letra y un color especial. Apliquemos el primer estilo a un texto en HTML. span class=”estilo1” id=”texto”Texto con estilos/span En este caso, mediante el uso de class, asignamos el primer estilo a la frase Texto con estilos. Podemos ver el resultado en la siguiente imagen: 8. EL NAVEGADOR Y SU DOMINIO 318 _` El desarrollo web ha evolucionado tanto a lo largo de los años que la aplicación de los formatos vi- suales a textos, imágenes, colores de fondo, posición de distintos elementos y otros aspector pa- só de ser declarado con etiquetas HTML al uso total de las hojas de estilo. Al momento de diseñar nuestros sitios web, es una buena práctica aplicar esta técnica por sobre el uso de tags HTML. DE HTML A CSS 08_Silverlight.qxp 9/30/09 1:36 PM Page 318
  • 321.
    Figura 26. Eltexto se muestra con las características del primer estilo creado. Si tomamos el elemento desde la página web desde su HTML, mediante el identifica- dor del elemento, estaremos en posición de modificar el estilo por otro de la lista de es- tilos creados con anterioridad, una vez presionado el botón en la aplicación Silverlight. private void Button_Click(object sender, RoutedEventArgs e) { HtmlPage.Document.GetElementById(“texto”).CssClass = “estilo2”; } Figura 27. El formato de la frase cambió de acuerdo con el segundo estilo declarado. Silverlight 2 y el HTML 319 08_Silverlight.qxp 9/30/09 1:36 PM Page 319
  • 322.
    Otra posibilidad, sino contamos con una estructura de estilos predefinida, es la de modificar los valores de los estilos en el elemento HTML, utilizando el nombre de la propiedad que hace referencia al estilo que queramos modificar. private void Button_Click_1(object sender, RoutedEventArgs e) { HtmlElement etiqueta = HtmlPage.Document.GetElementById(“texto2”); etiqueta.SetStyleAttribute(“border”, “dashed 3px black”); etiqueta.SetStyleAttribute(“color”, “red”); } Por cada estilo que deseemos aplicar, necesitamos realizar una llamada al método SetStyleAttribute(), especificando el nombre del estilo y su valor. Observemos, en la siguiente figura, cómo se visualiza el elemento HTML antes de aplicar un estilo y cómo queda luego su posterior transformación. Figura 28. A izquierda, vemos una etiqueta sin estilo alguno. Al procesar el código Silverlight, éste aplica los estilos especificados. SILVERLIGHT 2 Y JAVASCRIPT Así como hemos podido interactuar con el HTML contenedor de la aplicación Silver- light, también es posible hacerlo con el código JavaScript que se ejecuta en el navega- dor. Esta característica puede resultar muy valiosa si tenemos en cuenta el uso actual que se le da a la Web y todas las tecnologías involucradas. Por ejemplo, la implemen- 8. EL NAVEGADOR Y SU DOMINIO 320 08_Silverlight.qxp 9/30/09 1:36 PM Page 320
  • 323.
    tación de A.J.A.X.,tecnología que le da vida a la Web 2.0, se nutre profundamente de JavaScript, por lo que tener control sobre este lenguaje, desde Silverlight y hacia él, pue- de potenciar mucho más las posibilidades de desarrollo de aplicaciones web. Como primera instancia, asociaremos un evento JavaScript a un elemento HTML que, cuan- do se ejecute, será capturado por la aplicación Silverlight para manejar este proceso. private void Button_Click(object sender, RoutedEventArgs e) { HtmlElement elemento = HtmlPage.Document.GetElementById(“contenedor”); elemento.AttachEvent(“onclick”, BotonCliente_Click); } private void BotonCliente_Click(object sender, HtmlEventArgs e) { ... ... Las líneas anteriores toman un elemento HTML, para este caso, un botón, y adjuntan, al evento OnClick de JavaScript para ese botón, un manejador que se encontrará tra- bajando en la aplicación Silverlight. Cuando el usuario presione sobre el botón HTML, el método BotonCliente_Click se disparará y podremos ejecutar nuestro código. Figura 29. El evento fue disparado desde el cliente. Una vez disparado, podríamos ejecutar la lógica de la aplicación como para llamar a servicios web que retornen información, o construir nuevo HTML para el usuario. Esto puede convertirse en una herramienta poderosa si quisiéramos encapsular lógi- Silverlight 2 y JavaScript 321 08_Silverlight.qxp 9/30/09 1:36 PM Page 321
  • 324.
    ca de códigodentro de un lenguaje común como C# o cualquiera que utilicemos con Microsoft .Net. Pensemos que, muchas veces, la depuración de código JavaScript puede resultar compleja al extremo, incluso lenta, a medida que este código sube en dificultad. Conectarse a servicios web podría requerir de cientos de líneas de código, incluyendo el análisis del XML retornado por éste, así como el manejo de errores de conexión y demás. Por otro lado, podríamos llevar esta lógica a un componente Silverlight sin interfaz visual que se encargue de capturar cada uno de los eventos pro- ducidos en JavaScript por el cliente y manejarlos como si se tratase de una aplicación creada con Microsoft .Net. Esto podría ahorrarnos tiempo y esfuerzo, así como dar- nos la posibilidad de realizar mantenimiento futuro al código de forma mucho más eficiente. Los controles HTML cuentan con una serie de eventos a los que podemos subscribir los eventos Silverlight. Éstos se listan a continuación: • onchange: este evento se disparará cuando el control asociado sufra una modifica- ción. En el caso de cajas de texto, si el usuario modifica su contenido; y en listas desplegables, si otro elemento de la lista es seleccionado. En la mayoría de los ca- sos, el control deberá perder el foco para que el evento aplique. • onclick: se dispara cuando el usuario presiona el elemento con el mouse. • onmouseover: éste se disparará cuando el mouse pase por arriba del elemento. Jun- to con los valores pasados por argumento, se podrán encontrar las coordenadas por las cuales el mouse se mueve. • onmouseout: en el momento en el que el mouse deje la superficie del control HTML, este evento nos avisará. • onkeydown: si el usuario presiona una tecla cuando está dentro de un elemen- to, por lo general representado por una caja de texto, podremos saber qué tecla es la que está presionando. • onkeyup: si el usuario deja de presionar una tecla del teclado, el evento nos avisará. • onkeypress: si el usuario presionó y soltó una tecla, este evento se disparará. • onfocus: este evento será ejecutado cada vez que un control tome el foco. Esto es, que el cursor de escritura esté sobre él o si el usuario hubiera presionado con el botón del mouse sobre el control para conseguir el foco. • onblur: cada vez que un control pierda el foco, se disparará este evento. • onload: se dispara cuando la página termina de cargar todo su contenido. • onunload: cada vez que la página sea destruida, el evento nos avisará. Este even- to asume que la página será descargada de la memoria del navegador cuando naveguemos a otra página o cuando presionemos un vínculo que haga que el contenido de la página se recargue. Por consiguiente, podríamos subscribirnos a cualquiera de los eventos antes lista- dos. Debemos tener en cuenta que algunos eventos sólo son soportados por ciertos navegadores, por lo que deberíamos utilizarlos con cuidado. 8. EL NAVEGADOR Y SU DOMINIO 322 08_Silverlight.qxp 9/30/09 1:36 PM Page 322
  • 325.
    Llamar funciones Como dijimos,también es posible llamar a funciones JavaScript desde código Sil- verlight. Esto nos será de gran utilidad en casos en los que tengamos sitios web ya implementados, con lógica incluida en líneas de código JavaScript, y queramos ex- tender esa funcionalidad desde Silverlight. Lo primero que necesitamos es algo de código JavaScript para poder utilizarlo desde Silverlight. script language=”javascript” type=”text/javascript” function MostrarMensaje(mensaje) { alert(mensaje); } /script En este caso, sólo mostraremos un mensaje emergente, pasando un parámetro que representa el texto por mostrar. Desde Silverlight, usaremos el objeto HtmlPage y HtmlWindow para capturar el código JavaScript y ejecutarlo. HtmlPage.Window.Invoke(“MostrarMensaje”, “Mensaje desde Silverlight”); El primer parámetro del método Invoke() especifica el nombre de la función JavaScript por ejecutar. El segundo y todos los siguientes representan cada uno de los parámetros que la función JavaScript pudiera necesitar. Así, si tenemos más de un parámetro que pasar a la función JavaScript, podremos colocarlos separados por comas. Como vemos en la siguiente figura, el mensaje de alerta es ejecutado en forma correcta. Figura 30. Al presionar el botón, Silverlight llama y ejecuta la función JavaScript. También es posible utilizar otra forma de referenciar y de ejecutar código JavaScript. La siguiente línea hará el mismo trabajo que lo planteado en las líneas anteriores: ScriptObject script = (ScriptObject)HtmlPage.Window.GetProperty(“MostrarMensaje”); script.InvokeSelf(“Mensaje desde Silverlight. Nueva forma”); Silverlight 2 y JavaScript 323 08_Silverlight.qxp 9/30/09 1:36 PM Page 323
  • 326.
    En este caso,tomamos como una propiedad de la ventana actual el nombre de la función JavaScript y transformamos el resultado a un tipo ScriptObject, que alber- gará la función y su funcionalidad. En la Figura 31, observamos que el mensaje se despliega de la misma forma que en el caso anterior. Figura 31. Utilizando otra forma de ejecutar código, obtenemos similares resultados. Objetos Silverlight para JavaScript Silverlight también puede exponer métodos y funciones internas, como objetos JavaScript. En los apartados anteriores trabajamos con eventos y los ejecutamos de un lado y del otro, haciendo que Silverlight fuera el centro de atención, ya que éste se en- cargaba de la ejecución de funciones JavaScript, así como de la captura de eventos des- de el navegador cliente. Por otro lado, es posible dar mayor protagonismo a JavaScript haciendo que Silverlight exponga sus métodos y funciones para que sean consumidos desde el código cliente. Esta posibilidad nos acercaría más al concepto de usar Silverlight como un proveedor de funcionalidad compleja en casos donde la misma implemen- tación por parte de JavaScript acarrearía mucho más esfuerzo. Para lograr esto, es ne- cesario decorar, con un atributo, la clase Silverlight que se expondrá hacia JavaScript y, con un segundo atributo, cada método o función que necesitemos exponer. [ScriptableType()] public partial class Page : UserControl { public Page() { InitializeComponent(); HtmlPage.RegisterScriptableObject(“Silver”, this); } [ScriptableMember()] public void MostrarMensaje(string mensaje) { this.txtMensaje.Text = mensaje; } } 8. EL NAVEGADOR Y SU DOMINIO 324 08_Silverlight.qxp 9/30/09 1:36 PM Page 324
  • 327.
    La primera línea,ScriptableType(), marca la clase como un tipo que podrá ser con- sumido desde JavaScript. La siguiente línea: HtmlPage.RegisterScriptableObject(“Silver”, this); La línea anterior se encarga de registrar el código JavaScript que servirá de interfaz entre Silverlight y el código JavaScript que consuma esta funcionalidad. Para esto, es necesario especificar un nombre de objeto y la clase que se usará como punto de entrada del script. Por su parte, la línea ScriptableMember() hace referencia a los mé- todos y funciones que podrán ejecutarse desde JavaScript. Podremos tener tantos ScriptableMember() como funciones o métodos queramos exponer. Una vez expuesta esta información, podremos consumirla de la siguiente forma: script type=”text/javascript” function Mostrar() { var micontrol = document.getElementById(“AplicacionSilverlight”); micontrol.content.Silver.MostrarMensaje(“Mensaje desde JavaScript.”); } /script El código JavaScript anterior captura el objeto Silverlight embebido en la pági- na web. Este control se identifica mediante el uso del atributo ID dentro de su propia declaración, como podemos ver en el siguiente código: object id=”AplicacionSilverlight” data=”data:application/x-silverlight-2,” type=”application/x-silverlight-2” width=”400” height=”200” param name=”source” value=”ClientBin/Capitulo8JavaScript2.xap”/ param name=”onerror” value=”onSilverlightError” / ... ... Luego, se utiliza la referencia al objeto creado desde Silverlight, llamado Silver, el cual contiene la función MostrarMensaje(). La función JavaScript Mostrar() es lla- mada para este caso desde el evento onclick de un botón HTML. input type=”button” value=”Mostrar mensaje” onclick=”Mostrar();” / Silverlight 2 y JavaScript 325 08_Silverlight.qxp 9/30/09 1:36 PM Page 325
  • 328.
    Figura 32. Alpresionar el botón, el mensaje enviado desde JavaScript se muestra en Silverlight. También es posible crear objetos más complejos para que sean consumidos desde JavaScript. Podemos exponer una clase por completo y que ésta pueda ser instan- ciada y consumida desde el código JavaScript. Veamos la siguiente clase: [ScriptableType()] public class Sumar2 { [ScriptableMember()] public long Sumar2Numeros(long valor1, long valor2) { return valor1 + valor2; } } Esta clase posee una función que retornará la suma de los dos parámetros enviados. Si registramos esta clase como código JavaScript del cual se pueda crear una ins- tancia, podremos acceder a ésta como si se tratase de código JavaScript. HtmlPage.RegisterCreateableType(“Sumar2”, typeof(Sumar2)); En este caso, el objeto por construir desde JavaScript se llamará Sumar2 y tendrá disponibles todos los métodos de la clase creada antes. Para obtener una instan- cia de este objeto en JavaScript, deberemos hacer lo siguiente: 8. EL NAVEGADOR Y SU DOMINIO 326 08_Silverlight.qxp 9/30/09 1:36 PM Page 326
  • 329.
    function Sumar() { varMiControl = document.getElementById(“AplicacionSilverlight”); var sumar2 = MiControl.content.services.createObject(“Sumar2”); alert(sumar2.Sumar2Numeros(10, 20)); } Figura 33. Al presionar el botón para sumar, obtenemos el resultado correcto. En la siguiente figura, podemos ver que el objeto creado, si bien es consumido desde JavaScript, en el momento en que se procesa es ejecutado en Silverlight. Esto significa que no se está creando código JavaScript que simule la funcionalidad crea- da en Silverlight, sino que se llama a la función en Silverlight previamente definida. Figura 34. La ejecución desde JavaScript dispara el código en Silverlight. Silverlight 2 y JavaScript 327 … RESUMEN En este capítulo hemos visto que Silverlight tiene la capacidad de salir fuera de su marco tra- dicional de ejecución e interactuar con el entorno dentro del navegador, tanto con el código HTML como con el código JavaScript. Este último es posible ejecutarlo, manipularlo y consu- mirlo para generar mayor interacción con nuestro sitio web y con el usuario. Gracias a esto, Silverlight no sólo otorga funcionalidad dentro de su modelo de ejecución, sino que también extiende las funcionalidades circundantes dentro del navegador web. 08_Silverlight.qxp 9/30/09 1:36 PM Page 327
  • 330.
    328 PREGUNTAS TEÓRICAS 1 ¿Quéobjeto debemos usar desde Silverlight 2 para obtener información de la página HTML contenedora de la aplicación? 2 ¿Es posible modificar los valores de los objetos creados en el código HTML desde Silverlight 2? 3 ¿Cuándo se usa el método GetElementById desde Silverlight 2? 4 ¿Cómo podemos ejecutar el envío de un for- mulario web desde Silverlight 2? 5 ¿Cómo podemos lanzar una nueva ventana del navegador desde Silverlight 2? 6 ¿Qué es una cookie? 7 ¿Cómo leemos y escribimos cookies desde Silverlight 2? 8 ¿Cómo podemos ejecutar código JavaScript desde Silverlight 2? 9 ¿Qué atributo decorativo necesitamos utili- zar para que el código Silverlight pueda ser ejecutado desde JavaScript? 10¿Qué eventos JavaScript se disparan sólo por medio de la acción del usuario? Nom- bre algunos de ellos. ACTIVIDADES EJERCICIOS PRÁCTICOS 1 Visite el sitio de CodePlex (www.codeplex. com/IronPython), para informarse de có- mo implementar tecnologías tales como IronPython y Silverlight 2. 2 Para conocer más sobre el uso de reflexión sobre Microsoft .Net, ingrese en http:// msdn.microsoft.com/es-es/. 3 Modifique el ejemplo de navegación por marcadores para incluir un nuevo control. 4 Con el nuevo control creado en el ejercicio anterior, utilice cookies para dirigir al usuario a la página que estaba viendo, en la aplicación Silverlight, antes de cerrar la ventana del navegador. 5 Pruebe crear una aplicación Silverlight que se visualice en modo de pantalla completa. 08_Silverlight.qxp 9/30/09 1:36 PM Page 328
  • 331.
    Silverlight fuera de Windows ProyectoMoonlight 330 Sistemas operativos 330 Versiones de Moonlight 331 Herramientas de desarrollo 331 Problemas conocidos 333 Apéndice A Silverlight es una tecnología provista y mantenida por Microsoft. Si bien esta compañía centra su desarrollo en los sistemas operativos con mayor uso en el mercado de computadoras de escritorio de la actualidad, como OS X de Apple y Windows, la comunidad también hace su trabajo, creando soporte para sistemas operativos como Linux y Unix. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 329
  • 332.
    PROYECTO MOONLIGHT Moonlight esun proyecto creado por la comunidad de desarrolladores y patro- cinado por la compañía Novell. El objetivo de Moonlight es el de poder crear y ejecutar aplicaciones Silverlight bajo sistemas operativos con base Linux y Unix. De esta forma, es posible llevar el uso de esta tecnología a la mayor gama de usua- rios, sin importar su sistema operativo e, incluso, su navegador. Teniendo en cuenta que de manera nativa Silverlight es soportado por Opera, Internet Ex- plorer y Firefox bajo Windows y OS X de Apple, con Moonlight se amplía el horizonte al ejecutar Silverlight en Linux con Firefox. Figura 1. En la dirección www.mono-project.com/Moonlight encontramos el sitio web del proyecto Moonlight. Sistemas operativos Moonlight fue diseñado para soportar diferentes sistemas operativos Linux, tanto para arquitecturas x86 de 32 Bits como x86-64 para 64 Bits. En la Tabla 1, podemos ver la lista de sistemas operativos y versiones de navegadores web soportados en cada caso. ARQUITECTURA SISTEMA OPERATIVO FIREFOX 2.0 FIREFOX 3.0 x86 (32 Bits) SUSE Linux Enterprise Desktop 10 Sí Sí openSUSE 11.0 Sí Sí openSUSE 11.1 Sí Sí Ubuntu 8.04 Sí Sí Fedora Core 9 Sí Sí x86-64 (64 bits) SUSE Linux Enterprise Desktop 10 Sí Sí openSUSE 11.0 No Sí Tabla 1. Sistemas operativos y navegadores web soportados por Moonlight. APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS 330 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 330
  • 333.
    En cuanto arequerimientos, para ejecutar una aplicación Silverlight desde Firefox, de- beremos contar con 128 MB de memoria RAM, en cualquiera de las arquitecturas. Versiones de Moonlight En la actualidad, Moonlight cuenta con soporte total para Silverlight 1.0. La nueva versión con soporte para Silverlight 2.0 continúa en desarrollo y tiene fecha de sali- da para septiembre de 2009. Esto puede ser un punto en contra para Moonlight y los usuarios de Linux, porque Microsoft ya cuenta con la versión 3 de Silverlight li- berada. Tengamos en cuenta que la capacidad de desarrollo y conocimiento sobre la tecnología Silverlight nace desde Microsoft, por lo que es natural pensar y esperar que la empresa esté un paso adelante en la entrega de nuevas versiones y de nuevas funcionalidades para sus productos, mientras que la comunidad debe esperar la sali- da de estos productos y tecnologías, analizarlos, estudiarlos, para luego poder imple- mentarlos. Este ciclo continuo de nuevas versiones y constante aprendizaje por parte de la comunidad acarrea este tipo de conflictos con las versiones, dejando a muchos usuarios desactualizados y desatendidos. De cualquier manera, la nueva versión de Moonlight pretende mostrar significantes cambios, como la inclusión de Deep Zoom, Microsoft Media Pack 2.0 para manejo de video y sonido, la posibilidad de utilizar los controles y componentes propuestos por Microsoft para Silverlight, entre otras características que lo acercan mucho más a su versión para Windows. Herramientas de desarrollo Si bien el comportamiento de la librería de clases provista por Microsoft es el mis- mo usado por Moonlight, los creadores de éste no recomiendan el uso de Visual Studio 2008 para la creación de aplicaciones Silverlight específicas para Linux. Es- to se debe a que, al estar Moonlight en continuo desarrollo, aún presenta ciertos errores, en especial para Silverlight 2, que podrían causar un comportamiento no esperado dentro de sistemas operativos basados en Linux. En todo caso, si qui- siéramos desarrollar directamente bajo Linux, los creadores recomiendan el uso de la herramienta de desarrollo llamada MonoDevelop. Proyecto Moonlight 331 Si queremos iniciarnos en el desarrollo de Moonlight o, simplemente, visualizar aplicaciones cre- adas con esta tecnología en Linux, es posible descargar el plugin de Moonlight de la siguiente página web: www.go-mono.com/moonlight. Allí también podemos encontrar instrucciones de instalación y el historial de cambios de la aplicación. DESCARGAR MOONLIGHT 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 331
  • 334.
    Figura 2. MonoDevelop,una herramienta gratuita creada por la comunidad desarrolladora de Mono y Moonlight. MonoDevelop es, también, una herramienta de uso libre y gratuito para el desarro- llo con Mono, lo que quiere decir que nos proveerá herramientas no sólo para el de- sarrollo de aplicaciones Silverlight, sino que podremos crear aplicaciones web y de escritorio para Linux utilizando Microsoft .Net Framework como modelo base y C# como lenguaje de desarrollo. A la fecha, MonoDevelop se encuentra en su versión 2, y, como en toda comunidad de código abierto, es posible participar en su mejora. Como ya dijimos, Moonlight es un proyecto de la comunidad para la comunidad. És- te es libre y de código abierto. Por tal motivo, si deseamos colaborar en su mejora con- tamos con la posibilidad de hacerlo. En el sitio web de Moonlight, podemos encontrar las direcciones de los servidores SVN (Subversion o repositorio de versiones), que nos darán acceso al código y a cada una de las versiones históricas de estos archivos. Si no contamos con un cliente SVN o herramienta similar, existen excelentes alterna- tivas gratuitas que hallaremos en Internet. Por ejemplo, TortoiseSVN, una de las re- comendadas y usadas ampliamente en el desarrollo de software. TortoiseSVN cuenta con versiones para arquitecturas de 32 y 64 bits. No sólo es útil para este caso especi- fico, ya que podemos sacarle provecho al incluirlo en nuestros desarrollos de software, y al utilizarlo con sitios web que brindan servicios gratuitos de almacenamiento para APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS 332 Es importante recordar que MonoDevelop es una herramienta de uso libre y gratuito, con la que podremos llevar nuestras aplicaciones .Net a la plataforma Linux, rompiendo la barrera tradicional entre sistemas operativos. Podemos descargar MonoDevelop desde la siguiente dirección: http://monodevelop.com. MONODEVELOP 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 332
  • 335.
    desarrollo de productosde software, como Google Code (http://code.google.com/ hosting/) o Microsoft CodePlex (www.codeplex.com), sitio que podemos utilizar como repositorio de código fuente. Además, es posible encontrar grandes cantidades de código de ejemplo para utilizar en nuestros proyectos. Figura 3. TortoiseSVN es una poderosa herramienta para el manejo de archivos históricos en el desarrollo de software. Figura 4. Google Code es un repositorio de código para alojar el código de nuestro proyecto y poder trabajar de forma colaborativa. Problemas conocidos Debido a que Moonlight se basa en el modelo de trabajo propuesto por Mono, las limitaciones de este último son traspasadas también a Moonlight y a la ejecución de Silverlight. Además, por estar un paso atrás en el soporte de las versiones ofi- ciales de Silverlight, otros problemas relacionados con la funcionalidad misma de Proyecto Moonlight 333 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 333
  • 336.
    Silverlight aparecen enMoonlight. Una de las destacadas y heredadas del modelo de trabajo Mono que sustenta Moonlight es la falta de implementación de LinQ en su totalidad, por lo que es recomendable no utilizar este tipo de consultas integradas dentro del código que realicemos bajo Linux. Por otro lado, el modelo de trabajo Mono está enfocado para soportar y simular funcionalidad presentada en Microsoft .Net Framework 2.0. Como en el transcurso del libro trabajamos con funcionalida- des presentes en Microsoft .Net Framework 3.0 y 3.5, puede que la mayoría del có- digo presentado deba ser adaptado a la versión 2.0 de Microsoft .Net Framework. De cualquier manera, no todo está rodeado de malas noticias, ya que la comunidad detrás de Moonlight es una comunidad activa y en constante crecimiento Ésta hará de Moonlight un sistema cada vez más robusto y funcional con el correr del tiempo, a medida que se sumen más personas con espíritu colaborativo que quieran apoyar el desarrollo de mejora del proyecto. Figura 5. En el sitio web de Moonlight, se listan algunos sitios con los que se prueban las diferentes versiones de esta herramienta y su resultado al ejecutar aplicaciones Silverlight. Como vimos, Moonlight es un gran proyecto propuesto por la comunidad desa- rrolladora de código libre y abierto y, si bien puede estar desfasado en relación con las nuevas versiones de Silverlight producidas por Microsoft, no deja de ser un com- ponente que evoluciona día a día y que permite, con facilidad, mover la tecnología Silverlight a ambientes donde no llegaría por sí sola. No dudemos en apoyar este ti- po de emprendimientos y desarrollos que nos permiten obtener mayor cantidad y mejor calidad de productos de software. APÉNDICE A. SILVERLIGHT FUERA DE WINDOWS 334 09_Silverlight_Apendice.qxp 9/30/09 1:37 PM Page 334
  • 337.
    Silverlight 3, la nueva generación Silverlight3 336 Nuevos controles 336 Efectos en tres dimensiones 337 Uso de Pixel Shader 338 Fuera del navegador 339 Apéndice B En el momento en que se edita este libro, Microsoft saca a la luz la versión 3 de Silverlight. Por eso, en este apartado, tocaremos los temas más importantes que diferencian a Silverlight 2 de Silverlight 3, para así poder acoplarnos con facilidad a esta reciente tecnología. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 335
  • 338.
    SILVERLIGHT 3 Silverlight 3viene con grandes mejoras para el desarrollador, algo que también se tra- duce en progresos para el usuario. Mejor uso del hardware del equipo cliente, imple- mentación de funcionalidades de tres dimensiones, mayor soporte para formatos de video y sonido, y la posibilidad de ejecutar la aplicación fuera del navegador son sólo algunas de los nuevos adelantos. Curiosamente, el tamaño del plugin para descargar por los navegadores es apenas menor que el de la versión anterior, lo que también nos dice que el código de éste se ha optimizado de manera sustancial al incorporar mayor funcionalidad con menos líneas de código por parte de su motor de ejecución. Nuevos controles En esta entrega de Silverlight 3, fueron agregados nuevos controles. Muchos de éstos son para satisfacer necesidades puntuales sobre carencias anteriores. A la hora de desarrollar aplicaciones, es común encontrarse con necesidades básicas sobre el comportamiento de los controles, por lo que, si la tecnología no trae la solución incluida en ella, es necesario construir líneas de código con funcionalidad para subsanar este problema. Por este motivo, es común que Microsoft, por cada en- trega de nuevas tecnologías, incorpore mayores controles de aquellos que recono- ce como necesarios por parte de los desarrolladores. Uno de estos controles es el campo de texto con la funcionalidad de autocompletar. Pasándole una fuente de datos cualquiera, es posible que este control muestre una lista desplegable con los elementos que coincidan con lo introducido por el usuario. input:AutoCompleteBox x:Name=”autoCompletar” IsTextCompletionEnabled=”True” Width=”200” Height=”30” /input:AutoCompleteBox Si tenemos cualquier fuente de datos, incluso servicios web o WCF de donde ob- tener esta información, este control nos mostrará los datos de cómo hacerlo. APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN 336 Para mantenerse actualizado sobre las nuevas funcionalidades incluidas en Silverlight 3, po- demos ver los videos tutoriales en el sitio web oficial de Silverlight. Debemos ingresar en el siguiente sitio para visualizar estos videos: http://silverlight.net/learn/. Vale aclarar que los videos se encuentran en inglés. ACTUALIZARSE 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 336
  • 339.
    Figura 1. Unalista desplegable basada en la selección del usuario. Otros controles como el TreeView (árbol jerárquico), ValidationSummary (resumen de validaciones) o DataPager (paginador) son también parte del nuevo abanico de controles y componentes disponibles en esta versión. Efectos en tres dimensiones Silverlight 3 adiciona la característica de manipular objetos bidimensionales en un es- pacio tridimensional. Si bien no incluye, aún, el manejo de objetos tridimensionales de forma nativa, sí es posible simular este comportamiento mediante un nuevo con- junto de transformaciones. Estas transformaciones son llamadas proyecciones, y tra- bajan manipulando el elemento dentro del espacio XYZ según los grados de rotación. Image Source=”bosque_pokemon.jpg” Width=”400” Height=”250” Image.Projection PlaneProjection RotationX=”50” RotationY=”30” RotationZ=”35” /PlaneProjection /Image.Projection /Image Veamos, en la Figura 2 de la próxima página, cómo la imagen transformada tiene la apariencia de estar realmente dentro de un espacio de tres dimensiones. También notemos que esta transformación genera un mejor aspecto que la que intentamos, en el capítulo 4, al modificar un control DataGrid para conseguir una apariencia de tres dimensiones. En ese caso, simulábamos este aspecto, pero el plano de pro- yección no era necesariamente correcto. Silverlight 3 337 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 337
  • 340.
    Figura 2. Unaimagen de dos dimensiones proyectada en un plano de tres. Este tipo de proyecciones no sólo se aplica a imágenes, sino que pueden ser usadas en cualquier control provisto por Silverlight. Otros atributos presentados por el modelo de proyección se refieren al punto de proyección. Así como teníamos un punto que representaba el eje de rotación de un elemento, este punto de proyec- ción sitúa ese eje de proyección también dentro del espacio de tres dimensiones, pudiendo modificar por completo el comportamiento y la visualización de los objetos. Uso de Pixel Shader Pixel Shader es un componente incluido en las actuales tarjetas de video presentes en los equipos hogareños. Este componente funcional permite manipular y tratar la sali- da del video a la pantalla, haciendo uso del procesador de la tarjeta video. Esto agiliza la puesta en escena de las imágenes, permitiendo aplicar ciertos tratamientos a éstas, antes de que sean mostradas. Como esta funcionalidad está impresa en el hardware de la tarjeta, los cálculos sobre las modificaciones resultan más rápidos que los realizados por líneas de código. Silverlight 3 hace uso de estas funcionalidades adicionando efec- tos de video que luego serán traducidos y ejecutados por el hardware del usuario. Image Source=”bosque_pokemon.jpg” Width=”400” Height=”250” Image.Projection PlaneProjection RotationX=”50” RotationY=”30” RotationZ=”35” /PlaneProjection /Image.Projection Image.Effect DropShadowEffect BlurRadius=”15” ShadowDepth=”10” /DropShadowEffect /Image.Effect /Image APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN 338 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 338
  • 341.
    En el casoanterior, aplicamos un efecto de sombra de manera dinámica, calculada en el momento mediante Pixel Shader. Otro efecto disponible desde Silverlight 3 es el de Blur o difuminado. Si bien estos dos los encontraremos incluidos por defecto y listos para usar, es posible, si tenemos el conocimiento, elaborar efectos propios con Pixel Shader, creando código en HLSL (High Level Shader Language o lenguaje de alto ni- vel para Shader), compilándolo e incluyéndolo en la aplicación Silverlight. Figura 3. Esta imagen cuenta con un cálculo de sombra dinámica mediante la aplicación de Pixel Shader Fuera del navegador Si bien todo el entorno de ejecución de Silverlight se encuentra dentro del navegador, la nueva versión nos permite configurar la aplicación fuera de él. Para esto, se requiere el consentimiento del usuario y algo de configuración de nuestra parte. Esta caracte- rística puede asestar un gran golpe a las típicas aplicaciones de escritorio, ya que con Silverlight obtenemos gran potencial de diseño, trabajando en la Web, y además aho- ra puede quedarse en el escritorio y ejecutarse desde éste. Podremos configurar estas ca- racterísticas desde las propiedades del proyecto, como vemos en la siguiente figura: Figura 4. Configuraciones necesarias para utilizar la aplicación desde el escritorio. Silverlight 3 339 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 339
  • 342.
    Al instalar yejecutar la aplicación desde el escritorio, veremos el mismo comporta- miento sumando las características configuradas desde las propiedades del proyecto, como se muestra en la Figura 5 y en la Figura 6. Figura 5. Instalación de la aplicación Silverlight en nuestro escritorio. Figura 6. La aplicación instalada, ahora puede ser ejecutada sin necesidad de contar con el navegador web. Silverlight 3 tiene aún muchas más novedades y sólo hemos visto algo superficial de todas las nuevas características que presenta. Si ya estamos desarrollando con Sil- verlight 2 y queremos ampliar nuestros horizontes en esta tecnología, lo que hemos visto nos puede servir como un buen punto de partida para investigar y ahondar más en Silverlight 3 y su nueva propuesta. APÉNDICE B. SILVERLIGHT 3, LA NUEVA GENERACIÓN 340 10_Silverlight_Apendice-b.qxp 9/30/09 1:38 PM Page 340
  • 343.
    Servicios al lector índice temático342 Sitios web recomendados 345 En este apartado encontraremos una lista de sitios web de alta utilidad para iniciarnos en el desarrollo de aplicaciones Silverlight, así como para obtener información de soporte para poder crear nuevas aplicaciones y quitar cualquier velo de duda sobre la implementación de código y la aplicación de técnicas novedosas relacionadas con esta tecnología. Silverlight SERVICIO DE ATENCIÓN AL LECTOR: usershop@redusers.com 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 341
  • 344.
    SERVICIOS AL LECTOR 342 Cookies314 CookieSilver 315 CSS 178, 317 Cursor 88 D Data 57, 218 DataContext 278 DataGrid 60, 68, 75, 132, 168, 231 DatePicker 60, 137, 147 DateTime 135, 145 Deep Zoom 199, 331 Depuración 62 Dibujar 213 Dibujo 46 DispatcherTimer 257 DisplayDate 143 DisplayMode 250 Distorsión 167 DLR 21 DoubleAnimation 171 E Escalar 165 Estilo 178 Etiquetas 22, 290 Evento 72, 83, 261 Expression Blend 26, 30 F Flash 15 FontFamily 127 FontSize 127 FontWeight 127 G GetAttribute 294 GetElementById 294 ÍNDICE TEMÁTICO A AJAX 15 Almacenamiento aislado 239 Animaciones 19, 45, 170, 175 App.Config 271 AS 250 ASP.net 64, 317 Autocompletar 336 AutoUpgrade 58 B Background 48 Barras de desplazamiento 98 Binding 276 BlackoutDates 142 Bool 135 Border 48, 101, 168, 183 BorderThickness 102 Button 67, 103, 183 C Caja de texto 128 Calendar 60, 139 Canvas 24, 92, 222, 229 CheckBox 106, 123 Clases 40 Class 318 Click 51, 71, 74, 103, 107, 198 ClientBin 203 Clip 217, 225 CLR 21 ColorAnimation 173 ComboBox 117 Componentes 46, 67 Context 236 Contraseña 130 Controles 24 Controles 46, 67 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 342
  • 345.
    GotFocus 84 Grid 67,84, 89, 279 GridSplitter 89 Grilla 47 GroupName 110 H Height 39, 85, 125, 302 Hilos 255 HLSL 339 Hojas de estilo 290, 317 HTA 83 HTML dinámico 15 HTML 290 HtmlDocument 292 HtmlPage 300, 323 HtmlWindow 305, 310, 323 HttpHandler 234 HyperlinkButton 113 I IHttpHandler 236 IIS 270 Image 105, 114, 123, 215, 222 InkPresenter 208, 225 InnerHTML 295 INPUT 297 IntelliSense 61, 70 Interactividad 31 IsEnabledChanged 84 IsolatedStorageFile 240 IsolatedStorageFileStream 240 IsolatedStorageSettings 240 J JavaScript 290, 320 Juego 222 K KeyDown 84 KeyUp 84 L LayoutUpdated 84 LinQ 21, 63, 74, 283 ListBox 124, 252 LostFocus 84 M Marcador 196 Margin 68 MarkerReached 197 MediaElement 48, 188, 216 MediaOpened 198 Moonlight 330 MouseMove 209 N Name 57 NavigateUri 113 Nodo 83 NoWrap 128 O OnClick 321, 325 Onerror 57 OneTime 280 OneWay 280 OnExit 43 OnStartup 43 OpenFileDialog 251, 254 P Param 57 Password 131 PasswordBox 130 PasswordChar 131 Pincel 211 Pixel Shader 338 Plantillas 58, 64, 178, 182 Plugin 56 PointAnimation 171 PopupWindow 308 Índice temático 343 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 343
  • 346.
    TextWrapping 128 Threads 255 TimelineMarker198 Timer 149, 256 Transformaciones 45, 158, 175 TransformGroup 158 Traslación 159 Trazado 218 T-SQL 74 TwoWay 280 U Uri 225, 231, 238 URL 230 Usabilidad 31 V Validadores 281 Video 194 VideoBrush 195 Visual Studio 24 W WCF 21, 239, 270 Web.Config 234, 271 WebClient 230 WebMethod 264 Width 39, 85, 138, 302 WMA 188 WMV 194 WPF 16, 37, 82 X XAML 16, 18, 21, 82, 148 XamlReader 238 XAP 114 XLinQ 230 XML 15, 22, 82 Z Zoom 207 Position 190 ProgressBar 148, 258 Punto de interrupción 62 R RadioButton 110, 123 Rotación 161 RSS 230 S ScaleTransform 165 ScriptObject 324 ScrollViewer 98 SDK 58 Seguridad 239, 263 SelectedItem 119 SelectionMode 140, 146 Servicios web 222 SetAttribute 295 SetProperty 317 SetStyleAttribute 320 ShowDialog 251 Slider 152, 191 SOA 19 SOAP 265 Sonido 188 Source 50 SourceName 196 StackPanel 95, 168, 181, 237 Storyboard 173, 256 Streaming 21, 188, 228 String 281 Stroke 213 Subnodo 83 T Tag 23, 82 Text 126, 183 TextBlock 24, 61, 120, 126, 153, 183, 236 TextBox 41, 67, 127 TextBoxStyle 45 SERVICIOS AL LECTOR 344 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 344
  • 347.
    Sitios web recomendados 345 SITIOSWEB RECOMENDADOS Memorabilia http://memorabilia.hardrock.com Hard Rock Café fue uno de los primeros sitios web en implementar la tecnología Silverlight de Microsoft. Este sitio en particular presenta una colección completa de objetos regalados por artistas dentro de una presentación Deep Zoom. Es reco- mendable ver las estampillas de cartas enviadas por Paul McCartney. PhotoSynth http://photosynth.net Este sitio web muestra el uso de la tecnología PhotoSynth creada por Microsoft Research. Esta tecnología tiene la función de generar espacios en tres dimensiones basados en fotografías. El software calculará los distintos puntos que componen un espacio sobre la base de todas las imágenes disponibles de ese espacio. 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 345
  • 348.
    SERVICIOS AL LECTOR 346 Bing www.bing.com Elnuevo buscador de Microsoft incorpora funcionalidad creada con Silverlight para interactuar con distintos servicios propuestos por la compañía. Es posible guardar las búsquedas en SkyDrive, así como comentar y categorizar cada una de ellas. Sitio oficial de Silverlight www.silverlight.net Sitio oficial de Silverlight, donde podremos encontrar todo tipo de ejemplos sobre este software, así como herramientas y código pregenerado para usar en nuestros de- sarrollos. No debemos olvidarnos de visitar la sala de videos educativos del sitio. 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 346
  • 349.
    Sitios web recomendados 347 ComponentArt www.componentart.com Compañíaque provee controles y componentes de alta calidad para usar en el de- sarrollo de nuestras aplicaciones. Los últimos componentes creados por esta empresa incluyen varios destinados al uso dentro de aplicaciones Silverlight (son pagos). Infragistics www.infragistics.com Infragistics es otra empresa que provee controles y componentes visuales para el desa- rrollo de aplicaciones. Presenta un gran abanico de controles para Silverlight listos pa- ra usar. De igual forma que el sitio anterior, estos componentes y controles son pagos. 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 347
  • 350.
    SERVICIOS AL LECTOR 348 Quince http://quince.infragistics.com Sitiopropuesto por la empresa Infragistics que nos otorga una serie de patrones de diseño visual para aplicar en nuestros desarrollos. Con Quince, es posible entender cómo podemos mejorar la usabilidad de las aplicaciones desarrolladas por nosotros. Librería MSDN http://msdn.microsoft.com/en-us/library/cc838158(VS.95).aspx La librería MSDN para Silverlight propuesta por Microsoft es el manual de referen- cia a todas las clases, métodos, funciones, controles y componentes de Silverlight. Si te- nemos alguna duda sobre el desarrollo para Silverlight, es necesario acudir a este sitio. 11_Silverlight_servicios.qxp 9/30/09 1:39 PM Page 348
  • 351.
    Utilice nuestro sitiousershop.redusers.com: • Vea información más detallada sobre cada libro de este catálogo. • Obtenga un capítulo gratuito para evaluar la posible compra de un ejemplar. • Conozca qué opinaron otros lectores. • Compre los libros sin moverse de su casa y con importantes descuentos. • Publique su comentario sobre el libro que leyó. • Manténgase informado acerca de las últimas novedades y los próximos lanzamientos. También puede conseguir nuestros libros en kioscos o puestos de periódicos, librerías, cadenas comerciales, supermercados y casas de computación. Compra Directa! usershop.redusers.com usershop@redusers.com I ¥ (011) 4110.8700 V i s i t e n u e s t r o s i t i o w e b usershop.redusers.com Revise que haya un cuadro sobre el autor, en el que se informe sobre su experiencia en el tema. En cuanto a la editorial, es conveniente que sea especializada en computación. 1 Sobre el autor y la editorial Compruebe que el libro tenga guías visuales, explicaciones paso a paso, recuadros con información adicional y gran cantidad de pantallas. Su lectura será más ágil y atractiva que la de un libro de puro texto. 2 Preste atención al diseño Suele haber grandes diferencias de precio entre libros del mismo tema; si no tiene el valor en la tapa, pregunte y compare. 3 Compare precios No sólo el del texto; también revise que las pantallas incluidas en el libro estén en el mismo idioma del programa que usted utiliza. 5 Verifique el idioma Está en letra pequeña en las primeras páginas; si es un libro traducido, la que vale es la fecha de la edición original. 6 Revise la fecha de publicación Desde un sitio exclusivo en la Red hasta un CD-ROM, desde un Servicio de Atención al Lector hasta la posibilidad de leer el sumario en la Web para evaluar con tranquilidad la compra, o la presencia de adecuados índices temáticos, todo suma al valor de un buen libro. 4 Tiene valores agregados?? Claves para comprar un libro de computación. Adquiéralo con todos los medios de pago • Capítulo Gratis • Avant Première • Promoción • Ofertas * (*) Sólo válido para la República Argentina Catalogo_200RespRedes.qxd 11/21/08 2:21 PM Page 381
  • 352.
    Untitled-1 1Untitled-1 110/08/2009 12:28:3010/08/2009 12:28:30
  • 353.
    Untitled-1 1Untitled-1 110/08/2009 12:37:1910/08/2009 12:37:19
  • 354.
    Untitled-1 1Untitled-1 110/08/2009 12:56:1310/08/2009 12:56:13
  • 355.
    LA PREPARACIÓN IDEALPARA DESARROLLADOR CINCO ESTRELLAS DE MICROSOFT Ésta es una obra teórica y práctica para aprender a programar. Basado en el curso Desarrollador Cinco Estrellas de Microsoft, este material brinda las habilidades necesarias para iniciar el camino que nos lleve a convertirnos en desarrolladores de la plataforma .NET. DESARROLLADORES I 400 páginas ISBN 978-987-1347-74-2 Adquiéralo con todos los medios de pago • Capítulo GRATIS • Promoción • Ofertas • usershop.redusers.com RCT_Bombo_LIBROSilverlight.qxp 21/09/2009 16:10 Página 3
  • 356.
    por MATÍAS IACONO Eneste sitio encontrará una gran variedad de recursos y software relacionado, que le servirán como complemento al contenido del libro. Además, tendrá la po- sibilidad de estar en contacto con los editores, y de participar del foro de lecto- res, en donde podrá intercambiar opiniones y experiencias. Silverlight is the cross-platform, cross-browser plug-in for rich interactive applications and cutting-edge media experiences. With advanced tips from our expert, this book provides practical, grounded advice, and rich examples, to be ready for today´s challenges. SILVERLIGHT DESCUBRA UN NUEVO NIVEL EN EL DESARROLLO DE APLICACIONES PARA INTERNET Desde su lanzamiento, Silverlight se convirtió rápidamente en la opción multiplataforma ideal, tanto para desarrollar aplicaciones enriquecidas e interactivas, como para generar experiencias multimedia de vanguardia. Quien consiga dominarlo podrá ofrecer a sus clientes aplicaciones visualmente impresionantes, tiempos de respuesta sin comparación y requerimientos mínimos de ancho de banda, todas ventajas acordes a los tiempos de la incipiente Web 3.0. Esta obra ofrece un acercamiento profundo y práctico a esta herramienta, y está dirigida a desarrolladores con conocimiento de Microsoft .NET Framework, que deseen profundizar en el desa- rrollo Web. La enorme experiencia de Matías Iacono como desa- rrollador en esta plataforma lo convierte en el guía ideal para aportar consejos prácticos bien fundados, ejemplos enriquecedo- res y código optimizado para aplicar en sus propios proyectos. CONTENIDO N I V E L D E U S U A R I O PRINCIPIANTE INTERMEDIO AVANZADO EXPERTO 1 | INTRODUCCIÓN A SILVERLIGHT Experiencia de usuario y portabilidad | Arquitectura de Silverlight 2 | Microsoft .NET Framework | Interfaz de usuario y presentación | El código XAML | Herramientas de desarrollo 2 | MICROSOFT EXPRESSION BLEND 2 Silverlight con Expression Blend | Explorador de soluciones | Entorno | Barra de herramientas | Crear nuestra primera aplicación 3 | SILVERLIGHT PARA DESARROLLADORES Puesta a punto de Visual Studio 2008 | Crear la primera aplicación | Interoperabilidad con Expression Blend 2 4 | XAML AL EXTREMO El lenguaje XAML | Declaración de objetos | Controles y componentes | Grid | GridSplitter | Canvas | StackPanel | ScrollViewer | Border | Controles de iteración con el usuario | Button | CheckBox | RadioButton | HyperlinkButton | Image | ComboBox | ListBox | TextBlock | TextBox | PasswordBox | DataGrid | Calendar | DatePicker | ProgressBar | Slider 5 | LUZ, CÁMARA, ACCIÓN Mover objetos | Transformaciones de traslación, rotación, escalar y distorsión | Animaciones | DoubleAnimation | ColorAnimation | Estilos y plantillas 6 | CERRAR EL CÍRCULO MediaElement | Ejecutar sonidos | Elementos con video embebido | Deep Zoom | Dibujar con InkPresenter | Áreas de dibujo 7 | INTERCONEXIÓN Ampliar las funcionalidades | Silverlight desde C# | WebClient | Enviar información | Capacidad de almacenamiento | OpenFileDialog | Manejo de hilos | Temporizador | Hilos y eventos | Consumir servicios desde Silverlight | Manipular datos | LinQ 8 | EL NAVEGADOR Y SU DOMINIO Conectar tecnologías | Silverlight 2 y HTML | HtmlDocument y HtmlElement | HtmlPage | HtmlWindow | Cookies | Modificar CSS | Silverlight 2 y JavaScript | Llamar funciones | Objetos para JavaScript APÉNDICE A | SILVERLIGHT FUERA DE WINDOWS APÉNDICE B | SILVERLIGHT 3, LA NUEVA GENERACIÓN redusers.com SILVERLIGHT tapa Silverlight.qxp 21/09/2009 11:07 a.m. PÆgina 1