Visualizando datos con Silverlight PivotViewer

Microsoft ha liberado un control de usuario para la visualización de colecciones de datos con Pivot. Este control, similar a la aplicación PivotViewer nos permite crear aplicaciones silverlight, utilizando nuestras colecciones. Lo podemos descargar desde la web de Silverlight.

pivotviewer_1

Una colección es un conjunto de datos con características similares, que se pueden visualizar en web. La idea es parecida a las Pivot Tables de Excel, pero obteniendo la información visualmente.

Estas colecciones están compuestas de:

  • XML. Los elementos de la colección se definen en XML en un fichero cxml.
  • Imágenes. Las imágenes de la colección deben de estar en formato Deep Zoom.

Existen varias herramientas para crear las colecciones sin necesidad de código:

Estas herramientas nos permiten definir nuestras colecciones y generar los ficheros necesarios (cxml, deep zoom) para publicar la colección en un servidor web y poder enlazarla control Silverlight.

Otra opción sería utilizar el código de ejemplo que nos permite crear las colecciones en memoria, o incluso podríamos generar estas colecciones para almacenarlas en disco. Vamos a ver como se podría utilizar este código para crear una colección de los Twitter de un usuario.

Creando la colección

Para este ejemplo, vamos a crearnos una solución con los siguientes proyectos:

  • PivotServerTools. Este proyecto contiene las clases necesarias para la generación de la colección. Utilizaremos el mismo proyecto que viene en el ejemplo.
  • CollectionFactories. Este proyecto contendrá la factoría de colecciones. Aquí crearemos una clase que obtenga los datos de Twitter y genere la colección en memoria.
  • Aplicación web. Esta aplicación alojará la aplicación Silverlight y los HttpHandlers para generación dinámica de la colección.
  • Cliente Silverlight. Aquí tendremos el control PivotViewer enlazado a la colección dinámica.

La factoría de Twitter debe de implementar la clase PivotServerTools.CollectionFactoryBase, junto con el siguiente método:

   1:          public override Collection MakeCollection(CollectionRequestContext context)
   2:          {
   3:              string user = context.Query["user"];
   4:              string fileUrl = context.Query["url"];
   5:              if (string.IsNullOrEmpty(user) && string.IsNullOrEmpty(fileUrl))
   6:              {
   7:                  throw new ArgumentNullException("user", "Tiene que incluir un nombre de usuario Twitter en la URL ?user=<name>");
   8:              }
   9:   
  10:              string url;
  11:              if (!string.IsNullOrEmpty(user))
  12:              {
  13:                  url = string.Format("http://api.twitter.com/1/statuses/user_timeline.atom?screen_name={0}&count=200",
  14:                      HttpUtility.UrlPathEncode(user));
  15:              }
  16:              else
  17:              {
  18:                  url = fileUrl;
  19:              }
  20:   
  21:              string atom;
  22:              try
  23:              {
  24:                  using (WebClient web = new WebClient())
  25:                  {
  26:                      web.UseDefaultCredentials = true;
  27:   
  28:                      atom = web.DownloadString(url);
  29:                  }
  30:              }
  31:              catch (Exception ex)
  32:              {
  33:                  return ErrorCollection.FromException(ex);
  34:              }
  35:   
  36:              Collection collection = CollectionFromAtom(atom);
  37:              return collection;
  38:          }

En este método realizamos nuestra implementación que genera la colección obteniendo los datos de Twitter.

   1:  collection.AddItem(title, alternateUrl, null,
   2:                    new ItemImage(new Uri(imageUrl))
   3:                  , new Facet("Topics", TopicsInTweet(title))
   4:                  , new Facet("Users", UsersInTweet(title))
   5:                  , new Facet("Published", published)
   6:                  , new Facet("Links", HyperlinksInTweet(title))
   7:                  );

Se insertan cada uno de los mensajes del usuario en la colección creando las Facet, que serán utilizadas por el control PivotViewer para la ordenación y filtrado de los elementos.


La aplicación Silverlight con el control PivotViewer

Una vez que tenemos nuestro generador de colecciones, nos ponemos con nuestra aplicación Silverlight, que tiene que hospedar el control PivotViewer, utilizando un parámetro de inicialización que identifica la url de la colección que queremos visualizar. Definimos el control de usuario PivoViewer, añadiendo su namespace (xmlns:pivot) y la referencia a su ensamblado System.Windows.Pivot.

   1:  <UserControl x:Class="GSC.Twitter.Pivot.Silverlight.MainPage"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      xmlns:pivot="clr-namespace:System.Windows.Pivot;assembly=System.Windows.Pivot"
   7:      mc:Ignorable="d"
   8:      d:DesignHeight="300" d:DesignWidth="400">
   9:      <Grid x:Name="LayoutRoot" Background="White">
  10:          <pivot:PivotViewer x:Name="PivotViewer"
  11:                             Loaded="PivotViewer_Loaded"
  12:                             LinkClicked="PivotViewer_LinkClicked"
  13:                             ItemDoubleClicked="PivotViewer_ItemDoubleClicked" />
  14:      </Grid>
  15:  </UserControl>

Enlazamos la carga del control con el siguiente código, para que obtenga los datos de la colección utilizando el parámetro de inicio del control Silverlight.

   1:          private void PivotViewer_Loaded(object sender, RoutedEventArgs e)
   2:          {
   3:              App app = (App)App.Current;
   4:              string cxmlName = app.InitParamsCxml;
   5:              if (!string.IsNullOrWhiteSpace(cxmlName))
   6:              {
   7:                  LoadCollection(cxmlName);
   8:              }
   9:          }
  10:   
  11:          [ScriptableMember]
  12:          public void LoadCollection(string cxmlName)
  13:          {
  14:              string pageUrl = HtmlPage.Document.DocumentUri.AbsoluteUri;
  15:              string rootUrl = pageUrl.Substring(0, pageUrl.LastIndexOf('/') + 1);
  16:   
  17:              string collectionUrl = rootUrl + cxmlName;
  18:   
  19:              PivotViewer.LoadCollection(collectionUrl, string.Empty);
  20:          }

Sólo nos queda configurar los HttpHandlers en nuestra aplicación web para que cuando se realice una petición http sobre la colección, se ejecute nuestra Factory de Twitter y genere dinámicamente los datos de la colección a mostrar.

Nos creamos los siguientes HttpHandlers, para cada uno de los ficheros que vamos a generar desde el Factory de Twitter:

CXML

   1:      public class CxmlHandler : IHttpHandler
   2:      {
   3:          public void ProcessRequest(HttpContext context)
   4:          {
   5:              PivotHttpHandlers.ServeCxml(context);
   6:          }
   7:   
   8:          public bool IsReusable
   9:          {
  10:              get { return true; }
  11:          }
  12:      }

DZC

   1:      public class DzcHandler : IHttpHandler
   2:      {
   3:          public void ProcessRequest(HttpContext context)
   4:          {
   5:              PivotHttpHandlers.ServeDzc(context);
   6:          }
   7:   
   8:          public bool IsReusable
   9:          {
  10:              get { return true; }
  11:          }
  12:      }

DZI

   1:      public class DziHandler : IHttpHandler
   2:      {
   3:          public void ProcessRequest(HttpContext context)
   4:          {
   5:              PivotHttpHandlers.ServeDzi(context);
   6:          }
   7:   
   8:          public bool IsReusable
   9:          {
  10:              get { return true; }
  11:          }
  12:      }

ImageTile

   1:      public class ImageTileHandler : IHttpHandler
   2:      {
   3:          public void ProcessRequest(HttpContext context)
   4:          {
   5:              PivotHttpHandlers.ServeImageTile(context);
   6:          }
   7:   
   8:          public bool IsReusable
   9:          {
  10:              get { return true; }
  11:          }
  12:      }

DeepZoomImage

   1:      public class DeepZoomImageHandler : IHttpHandler
   2:      {
   3:          public void ProcessRequest(HttpContext context)
   4:          {
   5:              PivotHttpHandlers.ServeDeepZoomImage(context);
   6:          }
   7:   
   8:          public bool IsReusable
   9:          {
  10:              get { return true; }
  11:          }
  12:      }

y su correspondiente en el web.config que enlaza el código con las extensiones a controlar:

   1:        <httpHandlers>
   2:          <add path="*.cxml" verb="GET" type="GSC.Twitter.Pivot.Silverlight.Web.CxmlHandler"/>
   3:          <add path="*.dzc" verb="GET" type="GSC.Twitter.Pivot.Silverlight.Web.DzcHandler"/>
   4:          <add path="*.dzi" verb="GET" type="GSC.Twitter.Pivot.Silverlight.Web.DziHandler"/>
   5:          <add path="*/dzi/*_files/*/*_*.jpg" verb="GET" type="GSC.Twitter.Pivot.Silverlight.Web.DeepZoomImageHandler"/>
   6:          <add path="*_files/*/*_*.jpg" verb="GET" type="GSC.Twitter.Pivot.Silverlight.Web.ImageTileHandler"/>
   7:        </httpHandlers>

Sólo nos queda añadir el parámetro de inicio en el object de Silverlight:

   1:          <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
   2:            <param name="source" value="ClientBin/GSC.Twitter.Pivot.Silverlight.xap"/>
   3:            <param name="onError" value="onSilverlightError" />
   4:            <param name="background" value="white" />
   5:            <param name="minRuntimeVersion" value="4.0.50401.0" />
   6:            <param name="autoUpgrade" value="true" />
   7:            <param name="initParams" value="cxml=Twitter.cxml?user=adiazcan" />
   8:            <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none">
   9:                <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
  10:            </a>
  11:          </object>

y ya podemos visualizar las publicaciones de un usuario utilizando PivotViewer, por ejemplo, ordenando por Fecha de Publicación y visualizando en gráfico, como podemos ver en la siguiente imagen.

pivotviewer_2

Lo siguiente que veremos con PivotViewer es como generar un Factory para SharePoint 2010 y así poder visualizar, de una forma más dinámica, los perfiles de los usuarios.

 

Saludos a todos…

Deja un comentario

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