Silverlight: Simple RSS Scolling Banner
Para construir este ejemplo se ha utilizado Visual Studio 2008, los SDK de Silverlight 1.1 y las extensiones ASP.NET Futures.
Después de meses de la salida de silverlight 1.1, y sobre todo, a meses todavía de la versión 2.0, estoy intentado manejar un poco "todas" estas nuevas herramientas y sacar algo presentable.
La verdad es que no se si el resultado es presentable, pero, lo voy a postar de toda forma.
Lo que sigue es un banner hecho en xaml que, simplemente, visualiza el contenido de los titulos de una fuente rss. Nada de impresionante evidentemente pero, mirando el canal Bloomberg (Dial 18 en Digital +) de bajo tienen una banda que ha inspirado un poco todo esto.
Muy bien, el contenido del proyecto comprende un Servicio Web, destinado a resolver el problema que crea el BrowserHttpWebRequest, que, como explicado aquí, no soporta llamadas fuera del dominio (cross-domine call). (Esperemos que sea una limitación temporal).
El servicio web solo es un puente que permite descargar contenidos fuera de nuestro dominio, entonces, el unico metodo que por ahora escribimos es este que sigue.
[WebMethod]
public string DownloadData(string url)
{
try
{
return
Encoding.UTF8.GetString(new WebClient().DownloadData(url));
}
catch (Exception x)
{
return x.Message;
}
}
Bien, esto supera el problema del Cross-Domine! Desde nuestra Page.axml.cs ya podemos crear una instancia a nuestro servicio y descargar (también de forma asíncrona) el contenido de la pagina que deseamos.
Lo que sigue ahora es el archivo Xaml que pretende ser el banner para nuestra pagina.
<Canvas x:Name="parentCanvas"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Page_Loaded"
x:Class="SilverlightControls.Page;assembly=ClientBin/SilverlightControls.dll"
Width="640"
Height="25"
Background="#FF000000"
MouseEnter="Page_MouseEnter"
MouseLeave="Page_MouseLeave"
>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard x:Name="mainStoryboard">
<DoubleAnimation x:Name ="topAnimation"
Storyboard.TargetName="contxtTop" RepeatBehavior="Forever"
Storyboard.TargetProperty="(Canvas.Left)"
From="640" To="-640" Duration="0:0:30" AutoReverse="False" />
<DoubleAnimation x:Name ="downAnimation"
Storyboard.TargetName="contxtDown" RepeatBehavior="Forever"
Storyboard.TargetProperty="(Canvas.Left)"
From="640" To="-640" Duration="0:0:40" AutoReverse="False" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Canvas.Triggers>
<TextBlock FontSize="9" Foreground="White" x:Name="contxtTop" Height="28" Canvas.Top="1" Width="640" Visibility="Collapsed"/>
<TextBlock FontSize="9" Foreground="White" x:Name="contxtDown" Height="28" Canvas.Top="11" Width="640" TextWrapping="NoWrap" Visibility="Collapsed"/>
<TextBlock FontSize="9" Foreground="White" MouseLeftButtonUp="txInfo_MouseLeftButtonUp" x:Name="txInfo" TextWrapping="NoWrap" Width="640" Height="28" Canvas.Top="0" Visibility="Visible"></TextBlock>
</Canvas>
No hay mucho, lo único digno de comento es la "Sotyboard" que maneja dos textblock y permite que estos controles se desplacen de un lado a otro del Page. Para permitir que los títulos de nuestro rss sigan moviéndose los atributos "To" de cada elemento TargetProperty se han establecido con un valor negativo, esto permite que el textblok desaparezca a la izquierda de la pagina para aparecer desde la derecha.
El canvas registra tambien tres eventos, que declaramos en la clase, que son:
Loaded="Page_Loaded"
MouseEnter="Page_MouseEnter"
MouseLeave="Page_MouseLeave"
En orden, el loaded de la pagina descargará el contenido remoto a través de una llamada al servicio web, el Enter del mouse suspende la animación e visualiza informaciones acerca de la fuente que se muestra y, por ultimo, el Leave, reinicia la animación.
Codigo del Page.xaml.cs
Page Load:
string m_CurrentRSSUrl = "http://www.asp.net//news/rss.ashx";
public void Page_Loaded(object sender, EventArgs e)
{
InitializeComponent();txInfo.Text = "Downloading data from " + m_CurrentRSSUrl;
WebService service = new WebService();
service.BeginDownloadData(m_CurrentRSSUrl, new AsyncCallback(endDownloadData), service);
}
Como se puede leer, la llamada al método DownloadData es asíncrona, esto permite, eventualmente, añadir un mensaje de cargamento en el control antes que el servicio devuelva los rss. También se ha utilizado una variable global (CurrentRSSUrl) que registra la dirección del rss que deseamos descargar.
Ahora viene lo bueno. Silverlight, actualmente, dispone del objeto XmlReader que permite la manipulación de xml. Esta clase, como se verá, simplemente la utilizaremos para leer entre los elementos del archivo rss y crear una string de títulos seguidos.
void endDownloadData(IAsyncResult ar)
{
if (ar != null && ar.AsyncState != null && ar.IsCompleted)
{
try
{
WebService service = (WebService)ar.AsyncState;
String rawvalue = service.EndGetRSS(ar);
XmlReader xr = XmlReader.Create(new StringReader(rawvalue));bool itemSwitch = true;
while (xr.ReadToFollowing("item"))
{
xr.ReadToFollowing("title");
if (itemSwitch)
{
if (contxtTop.Text.Length > 0)
contxtTop.Text += " | ";
contxtTop.Text += xr.ReadElementContentAsString();
itemSwitch = false;
}
else
{
if (contxtDown.Text.Length > 0)
contxtDown.Text += " | ";
contxtDown.Text += xr.ReadElementContentAsString();
itemSwitch = true;
}
}txInfo.Text = m_CurrentRSSUrl;
txInfo.Visibility = Visibility.Collapsed;
contxtTop.Visibility = Visibility.Visible;
contxtDown.Visibility = Visibility.Visible;
}
catch (Exception x)
{
txInfo.Text = x.Message;
}
}
}
¡¡¡ Desafortunadamente no disponemos de dataset en silverlight 1.1 !!!
Todo lo que hacemos con este código es leer el contenido que nos devuelve el servicio web y añadirlo a nuestros dos textblock ya declarados en pagina.
contxtTop.Text += xr.ReadElementContentAsString(); y contxtDown.Text += xr.ReadElementContentAsString();