Definiendo el primer layout con Silverlight

Después de conocer los distintos tipos de proyectos disponibles con Silverlight 3, a día de hoy última versión estable (Silverlight 4 Beta disponible), podemos comenzar a crear una aplicación de lo más sencilla. Antes de comenzar con el layout, vamos a crear un proyecto de tipo Silverlight Application.

Al pulsar en OK nos aparece una nueva ventana:

En este cuadro de diálogo nos están ofreciendo la posibilidad de agregar además un proyecto web a la solución. Toda aplicación Silverlight necesita un soporte web donde insertarse, debido a la plataforma en la que se basa.
Seleccionamos la opción por defecto, que es ASP.NET Web Application Project, y pulsamos OK para que adjunte este proyecto a la solución.

 

Por defecto, la página de inicio en este caso sería PrimeraAppSLTestPage.aspx donde está incrustada la aplicación Silverlight, PrimeraAppSL, para poder mostrarla en el navegador. ¿Dónde está alojada la misma?

Si echamos un vistazo a la página generada observamos lo siguiente:

<%@ Page Language="C#" AutoEventWireup="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>PrimeraAppSL</title>
<style type="text/css">
html, body {
height: 100%;
overflow: auto;
}
body {
padding: 0;
margin: 0;
}
#silverlightControlHost {
height: 100%;
text-align:center;
}
</style>
<script type="text/javascript" src="Silverlight.js"></script>
<script type="text/javascript">
function onSilverlightError(sender, args) {
var appSource = "";
if (sender != null && sender != 0) {
appSource = sender.getHost().Source;
}

var errorType = args.ErrorType;
var iErrorCode = args.ErrorCode;

if (errorType == "ImageError" || errorType == "MediaError") {
return;
}

var errMsg = "Unhandled Error in Silverlight Application " + appSource + "n" ;

errMsg += "Code: "+ iErrorCode + " n";
errMsg += "Category: " + errorType + " n";
errMsg += "Message: " + args.ErrorMessage + " n";

if (errorType == "ParserError") {
errMsg += "File: " + args.xamlFile + " n";
errMsg += "Line: " + args.lineNumber + " n";
errMsg += "Position: " + args.charPosition + " n";
}
else if (errorType == "RuntimeError") {
if (args.lineNumber != 0) {
errMsg += "Line: " + args.lineNumber + " n";
errMsg += "Position: " + args.charPosition + " n";
}
errMsg += "MethodName: " + args.methodName + " n";
}

throw new Error(errMsg);
}
</script>
</head>
<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/PrimeraAppSL.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="3.0.40818.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40818.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
</form>
</body>
</html>

A parte de una pequeña definición de estilos y de la creación de una función javascript, que trata los errores que se puedan producir de Silverlight, vemos que se especifica un div dentro del formulario del body, el cual contiene un objeto con los parámetros relativos a nuestra aplicación, tales como el tipo de aplicación y versión, la ubicación de la aplicación, la función a la que debe llamar en caso de error (la función javascript mencionada anteriormente), el color de fondo, si está permitida la actualización del plugin de manera automática y un link de referencia al mismo por si no está instalado en el cliente.

LAYOUT

Para comenzar con algo simple, y suponiendo que tenemos nociones de Web Forms, vamos a enfocarlo de la siguiente manera: Imaginemos que tenemos un formulario con Web Forms de lo más simple con una serie de campos para rellenar y queremos pasarlo a Silverlight.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="AppWebForm._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="formulario" runat="server">
<div>
<div>
<asp:Label runat="server" AssociatedControlID="txtName" ID="lblName" Text="Name:" />
<asp:TextBox runat="server" ID="txtName" />
</div>
<div>
<asp:Label runat="server" AssociatedControlID="txtLastName" ID="lblLastName" Text="Last Name:" />
<asp:TextBox runat="server" ID="txtLastName" />
</div>
<div>
<asp:Label runat="server" AssociatedControlID="dddlGenre" ID="lblGenre" Text="Genre:" />
<asp:DropDownList runat="server" ID="dddlGenre">
<asp:ListItem Text="Female" Value="F" />
<asp:ListItem Text="Male" Value="M" />
</asp:DropDownList>
</div>
<div>
<asp:Label runat="server" AssociatedControlID="calBirthday" ID="lblBirthday" Text="Birthday" />
<asp:Calendar runat="server" ID="calBirthday" Caption="Birthday"></asp:Calendar>
</div>
<asp:Button runat="server" ID="btnEnviar" Text="Send" />
</div>
</form>
</body>
</html>

En Silverlight no utilizamos HTML para la creación de la interfaz de usuario sino XAML (eXtensible Application Markup Language), el cuál ya se utilizaba para Windows Presentation Foundation.

En el proyecto de Silverlight tenemos dos archivos con extensión xaml: App.xaml y MainPage.xaml. El primero de ellos se utiliza para declarar recursos compartidos y manejar eventos globales, de la misma manera que un archivo Global.asax en aplicaciones ASP.NET, y el segundo es donde definiremos la interfaz de usuario.

Para comenzar a “dibujar” la UI, abrimos el archivo MainPage.xaml donde inicialmente observamos el siguiente contenido:

<UserControl x:Class="PrimeraAppSL.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">

</Grid>
</UserControl>

En el primer etiquetado tenemos la defición del control, asociado a una clase que actuará como code behind, una serie de espacios de nombres y por último las medidas del control. Dentro de él, de forma predeterminada, se define un Grid.
Llegados a este punto, conviene hacer una distinción: Existen generalmente dos tipos de elementos dentro del layout: contenedores y controles. Todos ellos están incluidos dentro de System.Windows.Controls. Los que heredan de Panel se consideran contenedores, los cuales nos ayudarán a ubicar a los controles dentro de la interfaz. Los contenedores más comunes son el Grid, Canvas y StackPanel, aunque hay disponibles otros que veremos más adelante.

A grandes rasgos, podemos decir que el Grid posiciona sus elementos a semejanza de una tabla o cuadrilla, el Canvas los ubica de una forma similar a la que acostumbramos con CSS (Top, Left) y en el caso del StackPanel podemos utilizarlo, generalmente, como un conjunto de controles en línea dándole un sentido vertical o horizontal. Para este ejemplo utilizaremos el Grid como contenedor.

Antes de comenzar a añadir los controles, necesitamos definir cómo será nuestro Grid.

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PrimeraAppSL.MainPage"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot" Margin="5" Height="400" Width="400">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="60" />
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition MinWidth="60"/>
</Grid.ColumnDefinitions>
</Grid>
</UserControl>

En este caso, le estamos pidiendo que el contenedor esté compuesto de 5 líneas con un alto automático y un mínimo de 60 y dos columnas, la primera con un width determinado y la segunda con un mínimo de 60.
Por último, necesitamos añadir y posicionar los controles dentro del grid definido, por ejemplo de la siguiente forma:

<UserControl xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="PrimeraAppSL.MainPage"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot" Margin="5" Height="400" Width="400">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="60" />
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
<RowDefinition Height="Auto" MinHeight="60"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition MinWidth="60"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="ForeName" Text="Name:" Width="50" Height="25" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right"/>
<TextBox x:Name="txtName" Width="150" Height="25" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left"/>
<TextBlock x:Name="LastName" Text="Last Name:" Height="25" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
<TextBox x:Name="txtLastName" Width="150" Height="25" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"/>
<TextBlock x:Name="Genre" Text="Gerne:" Height="25" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
<ComboBox x:Name="comboGenre" Width="150" Height="25" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left">
<ComboBoxItem Content="Female"/>
<ComboBoxItem Content="Male"/>
</ComboBox>
<TextBlock x:Name="Calendar" Text="Birthday:" Height="25" Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right"/>
<controls:Calendar x:Name="BirthdayCalendar" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left"/>
<Button x:Name="buttonGrid" Content="Send" Width="100" Height="25" Grid.Row="4" Grid.Column="1"/>
</Grid>
</UserControl>

Para posicionar los controles dentro del Grid, tomando como primer valor el 0, usamos Grid.Row para indicar la fila y Grid.Colum  para la columna.

Si arrancamos la aplicación para comprobar el resultado, obtendríamos lo siguiente:

En una primera toma de contacto con XAML, hemos comprobado como podemos montar un formulario, bastante similar al anterior mostrado con Web forms, y posiblemente de una forma algo más atractiva sin realizar modificaciones de estilo considerables.

Adjunto el proyecto por si fuera de utilidad.

¡Saludos!

3 comentarios en “Definiendo el primer layout con Silverlight”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *