Silverlight 4 Beta – Impresión de Múltiples Páginas

En el artículo anterior, vimos los fundamentos del modelo de clases para imprimir desde nuestras aplicaciones de Silverlight 4.  Recordemos que la propiedad HasMorePages indica si nuestro documento tiene más páginas que imprimir; si HasMorePages es true entonces el evento PrintPage se disparará nuevamente hasta que HasMorePages sea false.

En este artículo veremos cómo aprovechar esta característica para poder mandar a imprimir un catálogo de artículos (en este ejemplo, un catálogo de álbumes de música) ya que este escenario será bastante común en las Aplicaciones de Línea de Negocio que construyamos con Silverlight 4.

Escenario

Dado el siguiente escenario:

1_thumb1

Podemos apreciar que tenemos un ListBox el cual contiene una lista de álbumes de música.  Además estamos cambiando el DataTemplate para poder mostrar de una mejor manera cada uno de esos elementos.  El siguiente fragmento de código muestra el Xaml de la aplicación:

<UserControl x:Class=”Demo.SL4.ImpresionMultiple.MainPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″
xmlns:local=”clr-namespace:Demo.SL4.ImpresionMultiple”
mc:Ignorable=”d”
d:DesignHeight=”300″
d:DesignWidth=”500″>
<UserControl.Resources>
<local:Albumes x:Key=”albumes” />
<DataTemplate x:Key=”VistaDataTemplate”>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”100″ />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border BorderBrush=”Black”
Padding=”3″
BorderThickness=”2″
CornerRadius=”10″>
<Image Source=”{Binding Foto}”
Width=”100″ />
</Border>
<StackPanel Grid.Column=”1″>
<TextBlock Text=”{Binding Titulo}”
FontSize=”20″ />
<TextBlock Text=”{Binding Banda}” />
</StackPanel>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name=”LayoutRoot”
Background=”White”
DataContext=”{StaticResource albumes}”>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto” />
<ColumnDefinition Width=”*” />
</Grid.ColumnDefinitions>
<ListBox Grid.Column=”1″
HorizontalAlignment=”Left”
Margin=”5″
Name=”listBox1″
VerticalAlignment=”Top”
Width=”450″
Height=”450″
ItemsSource=”{Binding}”
ItemTemplate=”{StaticResource VistaDataTemplate}” />
<StackPanel Height=”228″
HorizontalAlignment=”Left”
Name=”stackPanel1″
VerticalAlignment=”Top”
Margin=”5″>
<Button Height=”50″
Name=”button1″
Width=”120″>
<Button.Content>
<StackPanel>
<TextBlock HorizontalAlignment=”Center”>Imprimir</TextBlock>
<TextBlock HorizontalAlignment=”Center”>ListBox</TextBlock>
</StackPanel>
</Button.Content>
</Button>
<Button Height=”50″
Name=”button2″
Width=”120″>
<Button.Content>
<StackPanel>
<TextBlock HorizontalAlignment=”Center”>Impresión</TextBlock>
<TextBlock HorizontalAlignment=”Center”>Personalizada</TextBlock>
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
</Grid>
</UserControl>

Impresión de Elementos

La propiedad PageVisual del objeto de argumentos en el evento PrintPage indica ultimadamente cuál es el contenido a imprimir, siendo este contenido parte del árbol de Xaml o no.  Es decir que, si establecemos el ListBox como el PageVisual…

pd.PrintPage += (s, a) =>
{
//Establecemos el ListBox como el PageVisual
a.PageVisual = listBox1;
};

…nuestro resultado de impresión será el siguiente (impresión en XPS):

2_thumb1

Tal vez este mecanismo no sea el adecuado para presentar correctamente la impresión, ya que se imprime el elemento tal y como aparece en pantalla; es decir, una “fotografía” del elemento (incluyendo las barras de scroll, los bordes, etc.).

Impresión Personalizada

Podemos lograr un grado más alto de personalización creando de manera dinámica el contenido Xaml que deseamos imprimir.  En el caso de este ejemplo generaremos dinámicamente un Canvas que contenga un encabezado, además de un ItemsControl que despliegue todos y cada uno de los elementos a imprimir. Además de lo anterior, nos aseguraremos que la impresión permita múltiples páginas y que se impriman los registros en cada página de manera correcta.

Canvas

Tal como en el artículo anterior, creamos un Canvas que tenga el mismo tamaño del área de impresión disponible, según la impresora seleccionada:

pd.PrintPage += (s, a) =>
{
canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };

Encabezado

Para cada página a imprimir, se agregará un encabezado que contenga un logo a la izquierda, el título del encabezado centrado, y un texto que indique el número de página actual.

Nota: Hay un issue con Silverlight 4 Beta que impide la impresión de imágenes creadas dinámicamente.

Lista de Elementos

Esta es la parte más importante de este escenario.  Necesitamos soportar el hecho de que habrá más de una página al momento de imprimir.  En el ejemplo de este artículo tenemos un objeto llamado Albumes (List<Album>) el cual tiene un total de 42 álbumes.

Para la impresión personalizada crearemos otro DataTemplate llamado ImpresionDataTemplate el cual desplegará de manera diferente los mismos elementos de la pantalla.  Por ejemplo, quitaremos la imagen de cada álbum, además desplegaremos los elementos dentro de un Grid con cuatro columnas.  Las columnas que mostraremos serán Titulo, Banda, Inventario y FechaLanzamiento.  El siguiente fragmento de Xaml muestra el DataTemplate para la impresión:

<DataTemplate x:Key=”ImpresionDataTemplate”>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”150″ />
<ColumnDefinition Width=”120″/>
<ColumnDefinition Width=”100″ />
<ColumnDefinition Width=”100″ />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=”40″ />
</Grid.RowDefinitions>
<TextBlock Text=”{Binding Titulo}” FontWeight=”Bold” Grid.Column=”0″ />
<TextBlock Text=”{Binding Banda}” Grid.Column=”1″ />
<TextBlock Text=”{Binding Inventario}” Grid.Column=”2″ />
<TextBlock Text=”{Binding FechaLanzamiento}”
Grid.Column=”3″ />
</Grid>
</DataTemplate>

En el método de creación del listado por página (método CrearLista()) crearemos un ItemsControl el cual su DataTemplate sea el descrito arriba.  Asimismo, estableceremos como su fuente de datos (propiedad ItemsSource) únicamente los registros que quepan en la página actual.  Con los métodos de extensión Skip() y Take() podemos fácilmente leer cierto número de registros del objeto Albumes según la página actual.  El siguiente fragmento de código muestra este concepto:

void CrearLista(int pagina)
{
ItemsControl lista = new ItemsControl();
lista.Width = canvas.Width;
lista.ItemTemplate = this.Resources[“ImpresionDataTemplate”] as DataTemplate;

//Obtiene únicamente los registros que van en la página actual
//identificada en el argumento ‘pagina’ del método
lista.ItemsSource = fuenteDatos.Skip((int)(pagina*lineasPorPagina)).Take((int)lineasPorPagina);
//Agregamos la lista al Canvas
canvas.Children.Add(lista);

//Respetamos el alto del encabezado
Canvas.SetTop(lista, altoEncabezado);

//Incrementamos el contador
paginaActual++;
}

Finalmente, en el evento PrintPage invocamos los métodos de creación del encabezado y el de la creación de elementos por página:


CrearEncabezado(“Lista de Álbumes”);

CrearLista(paginaActual);

a.PageVisual = canvas;

a.HasMorePages = !(paginaActual == totalPaginas);

Muy importante en el código anterior es el valor de la propiedad HasMorePages.  En este ejemplo estamos indicando si hay más páginas siempre y cuando el contador (variable paginaActual) sea diferente al número total de páginas (variable totalPaginas).  Recordemos que si HasMorePages es true, el evento PrintPage nuevamente se disparará, provocando así la impresión de todas y cada una de las páginas del listado.

El resultado:

3_thumb1

Cabe mencionar que el DataTemplate específico para la impresión no es el único mecanismo para hacerlo de manera personalizada, también pudimos haber hecho un StackPanel o Grid de manera dinámica y leer programáticamente (un foreach tal vez) cada Album de Albumes programáticamente e ir agregando al contenedor los elementos manualmente.

Resumen

A través de la propiedad HasMorePages tenemos el control para indicar si nuestro documento a imprimir tiene múltiples páginas.  Asimismo vimos que un DataTemplate específico para la impresión es un mecanismo que nos facilita la manera en la que queremos que se imprima una lista de elementos en un reporte.

Pueden descargar el código fuente aquí

Pueden ver el demo en vivo aquí (requieres Silverlight 4 Beta instalado)

Silverlight 4 Beta – Impresión

Una de las características más esperadas y solicitadas por la comunidad de Silverlight es el soporte de impresión dentro de las aplicaciones, esto es, la capacidad de poder mandar a imprimir el contenido que estemos viendo en la aplicación ya sea una lista de datos de un DataGrid o ListBox o simplemente tomarle una “foto” a la pantalla y enviarla a papel o alguna de las impresoras virtuales instaladas en nuestros equipos (por ejemplo: OneNote, XPS, PDF, etc.).  Silverlight 4 Beta incluye esta característica a través de un modelo de clases muy sencillo.  De hecho este modelo me recuerda al modelo de impresión que tenemos en las aplicaciones Windows Forms desde hace ya mucho tiempo.

Clase System.Windows.Printing.PrintDocument

Las clases para el soporte de impresión dentro de Silverlight han sido incorporadas al espacio de nombres System.Windows.Printing, el cual contiene entre otras cosas la clase PrintDocument.  Esta clase PrintDocument es la clase responsable de mandar a imprimir el contenido que deseemos.

La clase PrintDocument no expone alguna propiedad para que podamos determinar el contenido que deseemos imprimir.  No obstante, el método Print() al ser ejecutado abre la caja de diálogo de impresión de nuestro sistema operativo.

1_thumb

Una vez seleccionada la impresora destino (física o virtual), disparará la siguiente secuencia de eventos:

  1. StartPrint
  2. PrintPage
  3. EndPrint
Evento StartPrint

El evento StartPrint se dispara una vez cerrada la caja de diálogo de selección de impresora.  Inmediatamente después se dispara el siguiente evento: PrintPage.

Evento PrintPage

Seguido del evento StartPrint se disparará el evento PrintPage.  Este es el evento más importante en el modelo de impresión ya que es en los argumentos donde debemos establecer efectivamente el contenido que deseamos imprimir.  Esto es definido en la propiedad PageVisual que es de tipo UIElement.  Ya que es de tipo UIElement podemos establecer como contenido en realidad cualquier cosa: ya sea que esté presente en el árbol de Xaml o que sea contenido creado de manera dinámica (a través de código o usando XamlReader.Load(), etc.).  Por ejemplo, si deseamos tomar una “fotografía” a la aplicación actual e imprimirla, podemos establecer como PageVisual el objeto contenedor raíz (ej. LayoutRoot).  O de lo contrario, si queremos crear una impresión personalizada podemos generar contenedores y elementos de manera dinámica tal y como lo muestra este artículo.

Además de la propiedad PageVisual contamos con un par de propiedades: HasMorePages y PrintableArea.

HasMorePages es una propiedad que indica si todavía hay más páginas que imprimir, por ejemplo en el caso de documentos largos, listas, catálogos etc.  Si establecemos esta propiedad a true, entonces el evento PrintPage volverá a dispararse.

PrintableArea indica el tamaño que tiene el área de impresión según la impresora seleccionada.  Por ejemplo no es el mismo tamaño si mandamos a imprimir a OneNote que a un PDF o a una impresora física.  Esta propiedad es de tipo Size y nos servirá también para calcular márgenes, posiciones de elementos, etc.

Cabe mencionar que, si la impresora seleccionada requiere todavía de la interacción del usuario, esta continuará (para indicar el nombre de un archivo .xps o .pdf por ejemplo).

Evento EndPrint

El evento EndPrint se disparará una vez terminado el proceso de impresión.

Ejemplo

Comencemos con crear un nuevo proyecto de Silverlight 4 a través de Visual Studio 2010 (Beta 2 es la versión más reciente en el momento de escribir este artículo).  A este proyecto le pondremos de nombre Demo.SL4.Impresion.  Visual Studio creará la solución junto con el proyecto adecuado tal y como lo esperamos.

Agregaremos a nuestro MainPage.xaml el siguiente código:

Los botones nos servirán para mandar a imprimir por medio de la ejecución del método Print() de la clase PrintDocument y el TextBlock nos servirá para identificar el estatus de la impresión.

En el clic del primer botón crearemos una nueva instancia de PrintDocument y estableceremos su propiedad DocumentName de manera adecuada.  El valor de esta propiedad será lo que aparezca en la ventana de estado de la impresora.

PrintDocument pd = new PrintDocument() { DocumentName = “Ejemplo de Impresión” };

Ahora bien, manejaremos el evento PrintPage.  En este caso usaremos una expresión lambda pero pudiera ser también un método:

En el código anterior suceden varias cosas:

Creamos un objeto de tipo Canvas, el cual nos servirá como lienzo para dibujar en él los elementos visuales que queramos imprimir (en este ejemplo el contenido será un TextBlock creado en el método CrearTitulo()).  El ancho y alto del objeto Canvas los establecemos a partir de la propiedad PrintableArea, la cual, nos indica el tamaño de impresión según la impresora seleccionada (por ejemplo, el área de impresión es diferente en OneNote que un .xps).

Finalmente, establecemos este contenido que creamos dinámicamente en la propiedad PageVisual.  Esta propiedad indica el contenido visual que vamos a imprimir.  El siguiente fragmento de código contiene todo el código completo de este primer ejemplo:

Canvas canvas = null;
int pagina = 0;

private void button1_Click(object sender, RoutedEventArgs e)
{
PrintDocument pd = new PrintDocument() { DocumentName = “Ejemplo de Impresión” };
pd.PrintPage += (s, a) =>
{
//canvas es una variable a nivel de clase
//Establecemos el ancho y alto de canvas a usando la propiedad PrintableArea
canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };

//Agregamos el título deseado para la página
CrearTitulo(“Esto es una Prueba de Impresión”);

//Establecemos el contenido en la propiedad PageVisual
a.PageVisual = canvas;
};
pd.StartPrint += (s, a) => textBlock1.Text = “Iniciando impresión…”;
pd.EndPrint += (s, a) => textBlock1.Text = “Impresión finalizada”;
pd.Print();
}

void CrearTitulo(string titulo)
{
//Crea un TextBlock que servirá como encabezado
TextBlock contenido = new TextBlock() { Text = titulo, FontSize = 20 };
contenido.Effect = new DropShadowEffect();
canvas.Children.Add(contenido);
Canvas.SetLeft(contenido, canvas.Width / 2 – (contenido.ActualWidth / 2));
}

Y el resultado, tanto en un archivo .xps como en OneNote:

2_thumb

3_thumb

Noten cómo también soporta Efectos visuales.  Tal es el caso del DropShadowEffect que se está estableciendo en el título.

En el segundo botón tendremos una ligera variante: mandaremos a imprimir varias páginas.  Esto es logrado a partir de establecer la propiedad HasMorePages = true.  En el caso de este ejemplo hemos establecido una variable a nivel de clase llamada pagina que nos servirá de bandera.  Esta bandera la estaremos revisando hasta que se completen 4 páginas en total.

pd.PrintPage += (s, a) =>
{
canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };
CrearTitulo(“Esto es una Prueba de Impresión”);
CrearSubtitulo(string.Format(“Página: {0}”, pagina+1));
a.PageVisual = canvas;

a.HasMorePages = !(pagina == 3);
pagina++;

};

Cabe recordar que al establecer la propiedad HasMorePages a true, el evento PrintPage se vuelve a disparar, de esta manera, podemos tener el control del contenido a imprimir en cada página.  El código completo se muestra a continuación:

void CrearSubtitulo(string titulo)
{
//Crea un TextBlock que servirá como subtitulo
TextBlock contenido = new TextBlock() { Text = titulo, FontSize = 14 };
canvas.Children.Add(contenido);
Canvas.SetLeft(contenido, canvas.Width / 2 – (contenido.ActualWidth / 2));
Canvas.SetTop(contenido, 40);
}

private void button2_Click(object sender, RoutedEventArgs e)
{
PrintDocument pd = new PrintDocument() { DocumentName = “Ejemplo de Impresión” };
pd.PrintPage += (s, a) =>
{
canvas = new Canvas() { Width = a.PrintableArea.Width, Height = a.PrintableArea.Height };
CrearTitulo(“Esto es una Prueba de Impresión”);
CrearSubtitulo(string.Format(“Página: {0}”, pagina+1));
a.PageVisual = canvas;

a.HasMorePages = !(pagina == 3);
pagina++;

};
pd.StartPrint += (s, a) => textBlock1.Text = “Iniciando impresión…”;
pd.EndPrint += (s, a) => textBlock1.Text = “Impresión finalizada”;
pd.Print();
}

El resultado final de la impresión de este segundo botón se muestra en la siguiente figura (las flechas rojas se añadieron posteriormente para indicar el número de cada página):

4_thumb

Resumen

Silverlight 4 Beta incluye la funcionalidad de impresión, a través de la clase System.Windows.Printing.PrintDocument.  Esta clase incluye el método Print(), que al ser ejecutado dispara una serie de eventos, entre ellos el evento PrintPage en donde podemos establecer el contenido deseado para imprimir, conocer el tamaño del área de impresión así como determinar si hay más páginas para imprimir (para escenarios de documentos de más de 1 página).

Puedes descargar el código aquí.

Puedes ver el demo en vivo aquí (requiere Silverlight 4 Beta instalado).

Creando contenido dinámico en PHP para Silverlight

Introducción

Como mencionábamos en el artículo anterior, Silverlight puede ser hospedado en prácticamente cualquier tecnología Web del lado del Servidor.  Asimismo podemos utilizar las características de la tecnología que estemos utilizando para poder crear Xaml de manera dinámica y enviar dicho contenido a la aplicación Silverlight ya sea a través de parámetros de inicialización (parámetro InitParams en <object>) o a través de un endpoint que podamos descargar por medio de un objeto de tipo WebClient.  Es este último caso el que usaremos en este artículo para crear contenido dinámico con PHP.

Creación del proyecto

Siguiendo los mismos pasos que usamos en el artículo anterior para la creación de un Sitio Web en IIS y una aplicación Silverlight, crearemos un nuevo proyecto de tipo Silverlight Application en Visual Studio .NET con el nombre PHPDynamicXaml.  Inmediatamente después de haber creado el proyecto borraremos los archivos Default.aspx y PHPDynamixXamlTestPage.aspx y sus archivos relacionados, dejando únicamente el archivo .html.

Agreguemos ahora un archivo llamado Content.php usando la plantilla de Archivo de Texto disponible al seleccionar la opción “Agregar nuevo elemento” en el menú contextual del proyecto.  La siguiente figura muestra la ventana de Solution Explorer y la Solución actual:

Será en el archivo Content.php en donde escribiremos el código necesario para la creación dinámica de contenido Xaml.  En nuestro ejemplo el contenido será una serie de rectángulos, el cual su número será definido por medio de un parámetro en el Querystring llamado r.  El siguiente fragmento ejemplifica el código de PHP necesario para la construcción dinámica de contenido en Xaml:

Es importante resaltar en especial la siguiente línea:

header(‘Content-Type: text/xaml’);

la cual establece que el tipo de contenido que regresará la página .php será de tipo Xaml (también funciona con el content type text/xml ya que Xaml no es más que Xml).  Lo anterior es de suma de importancia ya que estamos redefiniendo el comportamiento predeterminado que tiene PHP de regresar HTML.

Ahora bien, como podrán darse cuenta el código obtiene el número de rectángulos a crear por medio del parámetro r del Querystring.  Lo que hacemos es simplemente hacer un bucle for para la creación dinámica del Xaml que represente el número buscado de rectángulos.  Recuerden que cuando generamos Xaml dinámico es necesario incluir el xmlns por default en el contenedor raíz, si es que interpretaremos este código Xaml utilizando XamlReader.Load().

Lo que resta será escribir el código necesario en nuestra aplicación Silverlight para ejecutar la página php y obtener el resultado de su ejecución (lo cual será efectivamente contenido Xaml).  El siguiente código muestra el manejador del evento Loaded del UserControl MainPage:

La propiedad HtmlPage.Document.QueryString (parte del Puente HTML) permite leer el parámetro r que puede establecer el usuario en la página .html y que a su vez será utilizado para la invocación de la página Content.php.  El resto del código se encarga de obtener el resultado de la descarga del endpoint (Content.php) e interpretar el resultado por medio del método XamlReader.Load().

La siguiente figura muestra el resultado de ejecutar la siguiente página:

http://localhost:9050/PHPDynamicXamlTestPage.html?r=12

Lo anterior demuestra que PHP, además de permitirnos hospedar las aplicaciones Silverlight, lo podemos usar para la creación dinámica de contenido Xaml.

Hospedando aplicaciones Silverlight en PHP

Silverlight es una tecnología agnóstica tanto del lado del Cliente como del lado del Servidor, esto es, las aplicaciones de Silverlight pueden ser hospedadas en prácticamente cualquier tecnología Web del lado del Servidor (asp, jsp, php, cgi…) y pueden las aplicaciones Silverlight ejecutarse en la mayoría de los Navegadores modernos hoy en día (Firefox, Internet Explorer, Safari, Chrome…) en la mayoría de los Sistemas Operativos (Windows [2000,XP, Vista, 2003, 2008, 7…], Mac OSX y Linux [por medio del proyecto Moonlight creado por Novell]).  Es muy importante hacer notar lo anterior ya que hoy día aún existe mucha confusión acerca de Silverlight como plataforma para construir aplicaciones RIA.

Silverlight es una tecnología multi-Plataforma y multi-Navegador.

En este artículo veremos cómo podemos hospedar nuestras aplicaciones Silverlight en PHP e incluso cómo inicializar correctamente las aplicaciones por medio de parámetros creados del lado del Servidor con esta tecnología.

Instalando PHP sobre IIS (usuarios de Windows)

Una manera sencilla para ejecutar aplicaciones PHP sobre Windows es utilizar Web Platform Installer, la cual es una herramienta que nos permite instalar fácil y rápidamente plataformas o aplicativos completos en nuestros equipos locales.  En otros Sistemas Operativos la manera de ejecutar y hospedar aplicaciones PHP varía y está fuera de alcance de este artículo.  La siguiente figura muestra Web Platform Installer una vez instalado PHP:

Creando la aplicación de prueba

Crearemos una aplicación Silverlight 3 llamada SLPHP y aceptaremos la creación del sitio Web ASP.NET de prueba.  Esto es simplemente por conveniencia ya que la plantilla de Visual Studio creará el archivo SLPHPTestpage.html el cual cambiaremos su extensión a PHP.  Además de lo anterior agregaremos un elemento de tipo TextBlock en MainPage.xaml para poder apreciar que la aplicación hay sido cargada correctamente en la página (y no veamos la pantalla de color blanco únicamente)./

Tal cual, la página PHP está lista para utilizarse ya que estamos reutilizando todo el contenido de HTML que se ha generado para nosotros, no obstante primero tenemos que publicar nuestra aplicación en un Sitio Web en IIS para que el archivo .php sea identificado como tal.  Lo primero que necesitamos hacer es crear el Sitio Web en IIS (en mi ejemplo, físicamente en D:\SLPHP y en el puerto 9000).

Una vez con el Sitio Web creado, publicamos la aplicación desde Visual Studio .NET al fólder físico en donde está montado.

Al ver este Sitio Web en el navegador podemos darnos cuenta que efectivamente la aplicación es ejecutada en la página .php de manera correcta.  La siguiente figura muestra la aplicación de Silverlight 3 ejecutándose en la página PHP:

Inicializando Parámetros de la aplicación desde PHP

Como ya habíamos comentado y demostrado antes, es posible mandar valores de inicialización en las aplicaciones de Silverlight a través del parámetro InitParams del elemento <object>.  Esto nos permite establecer datos que sean necesarios para la aplicación Silverlight.  Hacer esto con PHP es sencillo si utilizamos la directiva <?php …. ?> justo en el sitio donde establecemos InitParams.  El siguiente fragmento de código muestra cómo se establecen dos parámetros llamados n y p los cuales tendrán el valor de lo que se envíe a través del Querystring:

Finalmente, podemos utilizar el valor que traen dichos parámetros dentro de la aplicación de Silverlight si los leemos en el evento Startup:

De esta manera, además de estar hospedando la aplicación de Silverlight en la página de PHP, estamos estableciendo algunos parámetros iniciales del lado del Servidor.

En próximos artículos veremos un poco más acerca de cómo integrar Silverlight con PHP.

Parámetros dinámicos en Silverlight 3 con <object>

Como sabrán una de las cosas que la versión final de Silverlight 3 no tiene es el control de ASP.NET AJAX para Silverlight (control <asp:Silverlight>).  Esto es un cambio de paradigma, para todos aquellos que estábamos acostumbrados a utilizarlo en nuestras páginas .aspx, ya que no tenemos una manera intuitiva de establecer las propiedades para el plugin de Silverlight 3.  El camino a seguir ahora es utilizar la etiqueta <object> de HTML.  Pueden encontrar una lista de los parámetros que podemos establecer para nuestras aplicaciones Silverlight en esta página del MSDN.

Ahora bien, la pregunta es: ¿cómo podemos establecer parámetros iniciales dinámicos del lado del servidor para el plugin de Silverlight?  Esto como recordarán estaba en la propiedad InitParameters del control <asp:Silverlight>, y al ser un control de servidor podíamos utilizarlo en el evento Page_Load de la página.  Con <object> este ya no es el caso pero de todas formas sí podemos establecer parámetros iniciales de manera dinámica del lado del servidor si utilizamos el control <asp:Literal> al agregar el parámetro initParams de la siguiente manera:

<param name=”initParams” value=’<asp:Literal runat=”server” ID=”parametros” />’ />

Esto nos permitire tener acceso programático del lado del servidor al control llamado ‘parametros’ y establecer en él cualquier valor que necesitemos.  El siguiente fragmento de código muestra el manejador del evento Load de la página aspx:

Como podemos apreciar, se están estableciendo dos parámetros iniciales: usuario y fecha.  Para leerlos lo hacemos de la manera tradicional, por medio de los argumentos del evento Application.Startup de nuestra aplicación Silverlight:

De esta manera, podemos sortear la falta del control asp:Silverlight en nuestros aplicativos de Silverlight 3.

Salu2!

Comportamientos de Física para Silverlight 3

Mi buen amigo y colega Andy Beaulieu MVP en Silverlight ha liberado una versión inicial de la biblioteca Physics Helper 3 en el sitio de Codeplex, la cual es una serie de Comportamientos para Silverlight 3 y Expression Blend 3 basados en el Motor de Física Farseer.  Como sabrán los Comportamientos es una característica nueva en Blend 3 y Silverlight 3 pensada en los diseñadores, la cual nos permite tener funcionalidad encapsulada para reutilizarla de manera declarativa en Blend, sin código!

Si quieren incluir conceptos de física en sus aplicaciones como gravedad, colisión entre elementos, aceleración, etc. no lo duden más y descárguenlo ya!

Problemas en Conexión Local de Silverlight 3 con IE8

Al parecer hay un problema en la versión final de Silverlight 3, cuando utilizamos la funcionalidad de Conexión Local.  El escenario es el siguiente:

En una aplicación en tengo un objeto de tipo LocalMessageSender para el envío de mensajes.  En otra aplicación (en otro proyecto diferente pero dentro de la misma solución) tengo un objeto de tipo LocalMessageReceiver.  Como sabrán ambas clases son el corazón de la funcionalidad de Conexiones Locales en Silverlight 3.  Ahora bien: si ejecutas cada aplicación en diferentes browsers pero del mismo tipo (ejemplo: IE-IE, FF-FF, Chrome-Chrome), funciona como debe ser, es decir, el mensaje es enviado del Sender al Receiver. 

El problema está cuando una de las dos aplicaciones la estás ejecutando en IE8 y la otra en otro tipo de navegador diferentes (FireFox o Chrome).  Parece ser que fuera-de-la-caja IE8 no permite tener una Conexión Local con otro tipo de navegador.  No obstante si haces la prueba entre FF-Chrome o Chrome-FF la Conexión Local de Silverlight 3 funciona a la perfección.

Este detalle lo encontré el día de hoy al impartir un Web Cast acerca de Silverlight 3 y aún no encuentro la solución al mismo.  Quiero pensar que es algún parámetro de configuración que me haga falta en IE8…

Tengo: Windows 7 64 bit, Visual Studio .NET 2008 c/SP1, SL3, SL3 Tools, IE8, Office 2010 CTP.

Les seguiré informando.

Silverlight 3 – Notas

El día de ayer, Tim realizó una presentación de Silverlight 3, justo en el momento en el que se liberaron los bits instalables al mundo entero. Durante la plática se tocaron muchos puntos importantes los cuales tomé nota y valen la pena que se los comparta.  Esta es simplemente una lista de notas rápidas que hice y no es una lista detatallada de las nuevas características que podrán encontrar en Silverlight 3, para esto les recomiendo que chequen este artículo o este otro.  Espero que les sea de utilidad.

OOB (Aplicaciones Fuera del Navegador)

  • Ahora puedes cambiar el tamaño de la página HTML en donde se ejecuta la aplicación OOB
  • Las imágenes que asignes como iconos deberán estar marcadas como Content, y deben ser archivos .png
  • Los archivos .ico no están soportados en Silverlight 3
    • No obstante un archivo .ico es generado de manera dinámica cuando la aplicación es efectivamente instalada en el equipo del usuario.  El .ico se genera a través de las imágenes .png que hayas asignado
  • Método Application.Current.Install() en vez de Application.Current.Detach()
  • Cuando instalemos una aplicación Fuera del Navegador, aparecerá un contador de 3 segundos en el botón de OK.  Esto como medida de seguridad.
  • El fólder donde se instalar ahora las aplicaciones es: C:\Users\[Nombre de Usuario]\AppData\LocalLow\Microsoft\Silverlight\OutOfBrowser
  • Sigue siendo un Sandbox
  • No está habilitado el HTML Bridge en OOB

General

  • No hay soporte para impresión nativo en Silverlight 3, pero sigue siendo WriteableBitmap una opción para capturar el render tree y guardarlo, o a través de HTML, o escribir un PDF en el servidor o escribir un XPS en el servidor
  • Blend 3 es RC no final
  • Visual Studio .NET 2010 soporta Silverlight 2 y Silverlight 3 Beta 1, para SL3 RTW hay que esperar a una actualización
  • ClearType disponible tanto para Windows como para Mac, con fonts nativos o embedded
  • Multi-touch en Silverlight 3 está soportado
  • SL3 no soporta el Sync Framework pero lo soportará después (lo tienen en su lista de pendientes)
  • Silverlight para Mobile sin noticias nuevas

Instalación de Silverlight 3 RTW

Hoy 09 de Julio 2009 ha sido liberada la versión final de Silverlight 3 RTW (RTW = Retail To Web).

Si son desarrolladores de esta tecnología y anteriormente ya tenían instalada la versión Beta 1 con las herramientas de Visual Studio, este artículo les servirá como guía de instalación de los nuevos componentes.

Desinstalación de componentes anteriores

Lo primero que necesitamos hacer es desinstalar los componentes y runtimes antiguos que tengamos instalados en nuestros equipos.  La siguiente figura muestra los componentes –en mi equipo- que tuve que desinstalar:

Instalación de las nuevas versiones

Descarguen e instalen los siguientes componentes, les recomiendo que inicien con el SDK:

  1. Silverlight 3 SDK
  2. Silverlight 3 Runtime
  3. Silverlight 3 Tools for Visual Studio .NET 2008
  4. Expression Blend 3 RC with SketchFlow RC

Listo!

La versión de Silverlight 3 final es: 3.0.40624.0

Salu2!

Subiendo archivos al servidor en aplicaciones Silverlight

Introducción

Es muy común que para nuestras aplicaciones Web necesitemos ofrecer a los usuarios la capacidad de subir archivos al servidor por diversas razones: para su posterior procesamiento, respaldo de información, etc.  En este artículo veremos cómo en Silverlight esta tarea es sencilla por medio de la clase WebClient.

WebClient.OpenWriteAsync()

La clase WebClient permite una comunicación asíncrona entre el aplicativo Silverlight y algún endpoint que deseemos leer o escribir.  Es precisamente por medio de su método OpenWriteAsync por el cual podemos establecer un Stream de escritura para poder grabar en el servidor algún archivo que el usuario seleccione en la aplicación por medio de la caja de diálogo OpenFileDialog.  Es de vital importancia el mencionar que Silverlight, al ejecutar bajo un esquema de confianza media (Medium Trust) debido a que corre en un SandBox, no es capaz de acceder el sistema de archivos de la máquina en donde está ejecutando la aplicación, sino solamente a través de la autorización del usuario por medio de la caja de diálogo mencionada.

Bajo estas premisas, desarrollaremos la siguiente solución que demuestra lo siguiente:

  1. El uso de la clase OpenFileDialog para permitir al usuario seleccionar algún archivo que quiera subir al servidor.
  2. El uso de la clase WebClient y su método OpenWriteAsync para poder escribir en un Stream la secuencia de bytes que representen dicho archivo.
  3. La creación de una página .aspx que obtenga el Stream y escriba el archivo en el servidor

La aplicación tendrá la siguiente interfaz de usuario:

El botón llamado btnUpload tendrá la responsabilidad de mostrar la caja de diálogo OpenFileDialog para que el usuario selecciones un archivo de su sistema de archivos local.  El archivo seleccionado está representado con la propiedad File del objeto OpenFileDialog, y utilizaremos el método OpenRead() para leerlo como un Stream.  Posteriormente guardaremos en una variable llamada bytes la secuencia de bytes del archivo.

El siguiente paso será crear el manejador del evento OpenWriteCompleted, evento que se dispara cuando se haya creado efectivamente el Stream de escritura en el servidor.  Es en este manejador de evento en donde escribiremos la secuencia de bytes del archivo (variable llamada bytes) en el Stream.

Posteriormente ejecutaremos el método OpenWriteAsync() de la clase WebClient, el cual nos permitirá crear un Stream de escritura en el endpoint especificado en el argumento.  En el caso de nuestra aplicación usaremos Upload.aspx, el cual es una página de ASP.NET que además le mandaremos como parámetro el nombre del archivo seleccionado para evitar tener un nombre de archivo ‘hard-coded’.

El siguiente fragmento de codigo muestra esta funcionalidad completa:

Upload.aspx

En este ejemplo estamos usando una página de ASP.NET llamada Upload.aspx, la cual obtiene el Stream que se escribió en el código anteriormente descrito, y que servirá para efectivamente guardar ese Stream como un archivo en el servidor.  El nombre para el archivo es determinado a partir del valor del parámetro n en el querystring.  En el caso de esta solución el archivo se escribirá en el fólder ClientBin en el servidor, aunque podría obviamente ser parametrizable la localización en el servidor (tal vez a través de otro parámetro en el querystring).

El siguiente bloque muestra el código completo de Upload.aspx:

Debemos mencionar que también sería posible reemplazar la página .aspx por una Handler .ashx e implementar en dicho archivo la funcionalidad descrita en el bloque de código anterior, también leyendo el Stream, obteniendo la secuencia de bytes y escribirla en el sistema de archivos.

Finalmente, la siguiente ilustración muestra la aplicación finalizada en donde podemos hacer lo siguiente:

  1. Hacer clic en el botón de Silverlight llamado ‘Subir archivo…’, esto invoca la caja de diálogo de Abrir archivo (Figura 1)
  2. Seleccionar el archivo y seleccionar OK (Figura 2)
  3. Se muestra el archivo seleccionado ya subido al servidor, en el fólder ClientBin el cual en este caso es el Sitio de Origen.

Resumen

Subir archivos al servidor es muy común en las aplicaciones Web y las aplicaciones de tipo RIA no están excluidas de ello.  En este artículo vimos cómo al utilizar las clases WebClient y OpenFileDialog podemos lograr esta funcionalidad en Silverlight y utilizar una página .aspx como puente para lograrlo.