Silverlight toolkit released
Con la versión final de Silverlight 2.0 pensaba que aparecería algun control de más que hemos echado en falta durarnte el periodo de Betas y demás. Por suerte en codeplex http://www.codeplex.com/Silverlight tenemos un set de controles típicos ya desarrollados.
Ha fecha de hoy existen dos conjuntos de controles, controles estables para ser usados tranquilamente y controles en pruebas:
En pruebas
AutoCompleteBox NumericUpDown Viewbox Expander ImplicitStyleManager Charting
Estables
TreeView DockPanel WrapPanel Label HeaderedContentControl HeaderedItemsControl
A disfrutarlos pues :)
Silverlight Beta2 to RTM: OnClick Event Failed
Volvemos a esta serie de posts relacionados con problemas que nos podemos encontrar a la hora de migrar una aplicación Silverlight Beta 2 a la versión final. En este caso supongamos que tenemos una aplicación silverlight con el siguiente código Xaml:
1: <Grid x:Name="LayoutRoot">
2: <Image Margin="0,0,0,0" Source="Images/background.jpg" Stretch="Fill" />
3: <Labs:Control1 HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
4: <Labs:Control2 Height="92.719" HorizontalAlignment="Left" Margin="8,8,0,0" VerticalAlignment="Top" Width="176"/>
5: <Labs:Control3 x:Name="mainMenu" HorizontalAlignment="Right" VerticalAlignment="Top"/>
6: </Grid>
Donde cada UserControl Control contienen un botón que responde al evento MouseLeftButtonUp.
¿Qué ocurre si migramos esta aplicación a la versión final de silverlight? Pues ocurre que no ocurre nada, es decir, por mucho que apretemos el botón izquierdo del ratón sobre el botón, contenido en cada control, no ocurre nada.
El por qué lo tenemos en el tipo de panel que contiene la imagen y los tres controles de usuario. ¿No veis que falte algo? Pues sí, no están definidas las filas ni las columnas. Otro de los problemas de la Beta 2 en cuenta a permisividad. Por tanto añadiendo la definición de filas y columnas y definición que parte del Grid ocupa cada objeto, el código fuente resultante y funcional seria el siguiente:
1: <Grid x:Name="LayoutRoot">
2: <Grid.RowDefinitions>
3: <RowDefinition Height="100"/>
4: <RowDefinition Height="*"/>
5: </Grid.RowDefinitions>
6: <Grid.ColumnDefinitions>
7: <ColumnDefinition Width="180"/>
8: <ColumnDefinition Width="*"/>
9: </Grid.ColumnDefinitions>
10: <Image Margin="0,0,0,0" Source="Images/background.jpg" Stretch="Fill"
Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Grid.ColumnSpan="2"/>
11: <Labs:Control1 HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2"/>
12: <Labs:Control2 Height="92.719" HorizontalAlignment="Left" Margin="8,8,0,0"
VerticalAlignment="Top" Width="176" Grid.Column="0" Grid.Row="0"/>
13: <Labs:Control3 x:Name="mainMenu" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Row="0" Grid.Column="1"/>
14: </Grid>
Ahora si que funcionan nuestros botones :)
Silverlight Beta2 to RTM: Catastrophic failure
Migrando y migrando aplicaciones, demos y demás que tengo por aqui en Silverlight Beta2 a la versión final, me he encontrado con problemas en tiempo de ejecución con un error que asusta al principio pero que investigando un poco se encuentra el por qué del mismo. El mensaje de error es: Catastrophic failure (Excepción de HRESULT: 0x8000FFFF (E_UNEXPECTED)), el cual lo podemos ver en la siguiente imagen.
El problema viene dado en la permisividad que nos daban las versiones Beta de Silverlight, a la hora de añadir elementos al diccionario de recursos de un elemento de tipo FrameworkElement. Es decir, el siguiente código fallaría una vez migrado a Silverlight 2.0:
Storyboard Story = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.To = -200;
da.Duration = TimeSpan.FromSeconds(20);
Story.Children.Add(da);
LayoutRoot.Resources.Add(null, Story);
Y la solución pasa por dar un valor correcto al parámetro key:
Storyboard Story = new Storyboard();
DoubleAnimation da = new DoubleAnimation();
da.To = -200;
da.Duration = TimeSpan.FromSeconds(speed);
Story.Children.Add(da);
LayoutRoot.Resources.Add("story", Story);
MIME Types: Could not download the silverlight application. Check web server settings
Ahora que ya tenemos Siverlight 2.0 en la calle, nos podemos animar a desplegar nuestra aplicación a nuestros servidores, empresas de hosting y demás donde tengamos nuestros sites alojados. ¿Qué puede ocurrir casi siempre?, que no tengamos bien configurados los MIME Types y por tanto al intentar ejecutar la aplicación una vez desplegada tengamos el siguiente error que se ve en la imagen:
La solución pasa por añadir los siguientes MIME Types necesarios para hacer funcionar nuestra aplicación Silverlight:
.manifest - application/manifest
.xaml - application/xaml+xml
.dll - application/x-msdownload
.application - application/x-ms-application
.xbap - application/x-ms-xbap
.deploy - application/octet-stream
.xps - application/vnd.ms-xpsdocument
.xap - application/x-silverlight-app
Silverlight 2 Release Candidate (Developer)
Un poco tarde…Sí! Pero más vale tarde que nunca. El pasado 25 de septiembre Scott Guthrie en su blog avisó de la publicación de la primera Release Candidate de Silverlight 2.
Es una buena excusa para ir migrando nuestras aplicaciones Silverlight Beta 2 a esta versión que ya será muy similar a la versión final para estar preparados. Entre otras cosas hay que tener claro que esta versión es la Developer Runtime, pensada precisamente para que nos vayamos preparando a la versión final los desarrolladores, más que los usuarios finales :)
Y como ya ocurrió con el paso de la Beta 1 a la Beta 2, existen los consabidos Breaking Changes entre la Beta 2 y la RC.
No descubrimos la pólvora si decimos que ya hay un documento donde se especifican dichos cambios cuando compilemos con la RC y aquello escupa errores a diestro y siniestro: Breaking Change Between Beta2 and Release
Y cosas nuevas y como podemos leer en el post de Scott, entre los controles tenemos: PasswordBox, ProgressBar y ComboBox (Ea, ya va tomando forma esto, ahora a ver si para la versión final nos añaden el un WrapPanel), solución de bugs, Skins Controls y demás.
Como menciona este hombre y aunque ya hay un post suyo sobre eso, me parece interesante escribir un post sobre Visual State Manager en Castellano y con su código de ejemplo para descargar.
Casi lo olvido, el link donde está dicha versión: http://silverlight.net/GetStarted/sl2rc0.aspx
Las Cosas Claras: Desde Javascript interactuar con Silverlight
En el último post de la serie esta que comencé de "Las Cosas Claras" estuvimos viendo como podíamos acceder al DOM del explorador para, en el ejemplo, llamar a funciones javascript. Pues bien, hoy veremos como hacer precisamente lo contrario.
En el siguiente ejemplo veremos como desde javascript podemos provocar cambios en el Silverlight, en este caso cambiar la orientación de los elementos de un StackPanel, pero también podríamos provocar el inicio de una animación o pararla, etc.
En primer lugar utilizaremos el siguiente namespace ya que contiene lo necesario para realizar esto:
using System.Windows.Browser;
Centrándonos en la página principal del Silverlight Page.xaml. El código XAML será muy sencillo, un simple StackPanel con varios botones:
<StackPanel x:Name="LayoutRoot" Background="White">
<Button Content="Rojo" Background="Red"/>
<Button Content="Verde" Background="Green"/>
<Button Content="Azul" Background="Blue"/>
<Button Content="Amarillo" Background="Yellow"/>
<Button Content="Blanco" Background="White"/>
<Button Content="Negro" Background="Black"/>
</StackPanel>
Y en el código fuente debemos registrar la clase MiTipoScriptable para poderla usar desde javascript de la siguiente manera:
- En el evento Loaded de la página registraremos el objeto que será usados para acceder desde javascript al método.
HtmlPage.RegisterScriptableObject("slObject", this);
- Y por último decoraremos un método de la clase Page, donde hemos realizado el registro del objeto del punto anterior, con el decorador [ScriptableMember] el cual será el método al que podremos llamar desde javascript.
[ScriptableMember]
public void slMethod(string o)
{
if (o != "H")
LayoutRoot.Orientation = Orientation.Vertical;
else
LayoutRoot.Orientation = Orientation.Horizontal;
}
Ahora nos vamos a la página ASPX desde la cual llamaremos al método slMethod del Silverlight. Para esto en primer lugar obtendremos el contenedor del Silverlight el cual en nuestro caso del ejemplo se llama SilverlightContainer y por último accederemos al método registrado mediante la siguiente sintaxis:
function Orientacion(oo)
{
var slPlugin = $get("SilverlightContainer");
slPlugin.Content.slObject.slMethod(oo);
}
PD: Se han creado dos botones Vertical y Horizontal que llamarán a la función Orientacion para cambiar el tipo de orientación del StackPanel.

Las Cosas Claras: Llamar funciones javascript desde Silverlight
Hoy veremos algo que nos puede resultar muy útil en nuestras aplicaciones Silverlight. Estamos hablando de la posibilidad de acceder al DOM (Document Object Model) del navegador para llamar a una función javascript que hará lo que queramos en el cliente.
Para ello necesitamos en primer lugar usar el siguiente Namespace:
using System.Windows.Browser;
En este namespace disponemos de la clase HtmlPage que será la que nos permita tener el acceso necesario al DOM del navegador.
Para este post he montado en un momentillo un ejemplo muy fácil. Son dos botones y una caja de texto. El primer botón llama a una función que muestra un alert con un mensaje predefinido en el cliente y el segundo botón muestra un alert con el texto del TextBox como mensaje. Algo sencillo pero que muestra lo más básico que podemos hacer: Llamar a una función con y sin parámetros.
En el código fuente podemos ver como utilizando el método GetProperty al que se le pasa el nombre de la función javascript, obtenemos un objeto de tipo ScriptObject. Este tipo de objeto dispone del método InvokeSelf que se encarga de hacer la llamada a la función en cuestión. Este método recibirá los parámetros que le serán pasados a la función javascript.
private void bttLaunch_Click(object sender, RoutedEventArgs e)
{
ScriptObject scriptMethod = (ScriptObject)HtmlPage.Window.GetProperty("MostrarAlerta");
scriptMethod.InvokeSelf();
}
private void bttLaunch2_Click(object sender, RoutedEventArgs e)
{
ScriptObject scriptMethod = (ScriptObject)HtmlPage.Window.GetProperty("MostrarAlerta2");
scriptMethod.InvokeSelf(txtMessage.Text);
}
Un muestra del resultado por ejemplo al pulsar el segundo botón seria el siguiente:
En el siguiente post de esta serie veremos como hacer lo contrario. Llamar desde el cliente, el navegador, a un función del Silverlight.
Twitter desde Silverlight Beta 2
Fácilmente! Esa es la forma en la que podemos obtener desde Silverlight Beta 2 nuestro post en Twitter. Este nos provee de una forma de obtener en diferentes formatos, nuestros últimos post y más información.
Con la siguiente URL: http://twitter.com/statuses/user_timeline/USERNAME.xml podemos obtener en formato XML los post y más información. Solo decir que debemos autenticarnos para poder recibir esta información.
Twitter provee los siguientes formatos: RSS, XML y JSON
Para más información sobre códigos de error posibles, limitaciones de uso, etc: Twitter API Documentation
En el ejemplo de hoy vamos a consumir el último mensaje del usuario de este blog FernandoBlog.
Para ello crearemos en primer lugar una aplicación Silverlight hospedada en un Sitio Web también creado en el mismo momento. De la forma en la que lo haremos, crearemos un servicio WCF que expondrá un método de obtención de los mensajes del usuario. En la siguiente imagen se puede ver las clases que necesitaremos para tal servicio:
- Service: Expone el contrato del servicio. En este caso dos métodos para obtener los mensajes del usuario identificado y otro para obtener los mensajes de un usuario a cuyos mensajes tenga acceso el usuario identificado.
- TwitterHelper: Es la clase que realiza la petición HTTP al API de Twitter y donde se procesan los datos recibidos
private List<TwitterPost> GetRequest(string uri)
{
WebRequest request = HttpWebRequest.Create(uri);
if (!string.IsNullOrEmpty(_ttUser) && !string.IsNullOrEmpty(_ttPwd))
{
request.Credentials = new NetworkCredential(_ttUser, _ttPwd);
}
WebResponse res = request.GetResponse();
StreamReader stream = new StreamReader(res.GetResponseStream());
TextReader reader = new StringReader(stream.ReadToEnd());
XDocument xDoc = XDocument.Load(reader);
return (from post in xDoc.Descendants("statuses").Descendants("status")
select new TwitterPost
{
Id = post.Element("id").Value,
CreatedAt = DateTime.ParseExact(post.Element("created_at").Value, "ddd MMM dd HH:mm:ss zzzzz yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal),
Text = HttpUtility.HtmlDecode(post.Element("text").Value)
}).ToList<TwitterPost>();
}
- TwitterPost: Representa un mensaje de twitter. El API devuelve mucha información que para este ejemplo solo con el Identificador, el texto del mensaje y la fecha de la creación del mismo nos es suficiente.
En la parte de Silverlight simplemente añadiremos una referencia la servicio WCF creado y haremos una llamada al método correspondiente.
public Page()
{
InitializeComponent();
ServiceClient client = new ServiceClient();
client.TwitterPostsCompleted += new EventHandler<TwitterPostsCompletedEventArgs>(client_TwitterPostsCompleted);
client.TwitterPostsAsync();
}
private void client_TwitterPostsCompleted(object sender, TwitterPostsCompletedEventArgs e)
{
List<TwitterPost> twitter = e.Result;
if (twitter.Count > 0)
{
TwitterPost lastTwitter = (from post in twitter orderby post.CreatedAt descending select post).First();
txtPost.Text = lastTwitter.Text;
txtTime.Text = RelativeCreatedAt(lastTwitter.CreatedAt);
}
}
Como curiosidad se muestra la función utilizada para mostrar la fecha de creación del mensaje en relación al día en la que se obtiene el mensaje desde Silverlight:
private string RelativeCreatedAt(DateTime _createAt)
{
TimeSpan _time = DateTime.Now.Subtract(_createAt);
int _days = Convert.ToInt32(_time.TotalDays);
if (_days > 0) return string.Format("Hace {0} dia{1}", _days, _days > 1 ? "s" : "");
int _hours = Convert.ToInt32(_time.TotalHours);
if (_hours > 0) return string.Format("Hace {0} hora{1}", _hours, _hours > 1 ? "s" : "");
int _minutes = Convert.ToInt32(_time.TotalMinutes);
if (_minutes > 0) return string.Format("Hace {0} minuto{1}", _minutes, _minutes > 1 ? "s" : "");
int _seconds = Convert.ToInt32(_time.TotalSeconds);
if (_seconds < 0) _seconds = 0;
return string.Format("Hace {0} segundo{1}", _seconds, (_seconds > 1 || _seconds == 0) ? "s" : "");
}
Finalmente el resultado sería el siguiente.

Silverlight Beta2: Crossdomain
Hasta la salida de la Beta 2 de Silverlight, cuando queríamos con la Beta 1 realizar una llamada un Servicio Web o WCF sabíamos que debíamos de colorar los ficheros Crossdomain.xml o ClientAccessPolicy.xml en el raíz del Sitio Web donde estuviese el Servicio a consumir por Silverlight. Silverlight por defecto irá a buscar el fichero ClientAccessPolicy.xml y sino lo encuentra buscará el Crossdomain.xml
Si hacemos pruebas desde Silverlight Beta2, nos encontraremos que aun teniendo estos ficheros, recibimos el siguiente error depurando:
El formato del fichero ClientAccessPolicy.xml que teníamos hasta ahora con el que conseguíamos que funcionase era:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from>
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Pero para esta versión necesitamos realizar un sutil cambio en el fichero:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
Ahora si que funciona nuestro Silverlight.
Movimiento Circular: Senos y Cosenos
¿Como nos pueden ayudar los Senos y Cosenos en nuestras aplicaciones Silverlight o Windows Presentation Foundation?
Imaginemos que tenemos una elipse y queremos que realice un movimiento circular. Utilizando las funciones trigonométricas Seno y Coseno de un ángulo dado podemos obtener el punto X e Y de la circunferencia imaginaria por donde queremos mover nuestra elipse.
Un ejemplo sencillo y que tal vez no tenga mucho sentido, pero que se puede ver el concepto del que estamos hablando: