LightSwitch | Aplicación LightSwitch para SharePoint

Estos días he tenido que trabajar con LightSwitch para crear una aplicación que se conectara a SharePoint que pudiera interactuar con una “Lista Personalizada” (Custom List).

Escenario

Antes de comenzar, es necesario que establezca el contexto en el que LightSwitch se convirtió en la opción buena o menos mala (según se mire). La idea era bien simple, tener una lista de SharePoint de tipo “Custom List” en la que insertar alertas y que éstas sean  notificadas por medio de Push Notifications a los usuarios con dispositivos Windows Phone. A priori esto podría resultar muy sencillo si disponemos de SharePoint Server 2013 server que ya dispone de un servicio de notificaciones, incluso en SharePoint 2010 server tampoco presenta un reto conseguir este objetivo pero, ¿qué ocurre con SharePoint Online? Independientemente de la versión, 2010 o 2013 preview, en el entorno online de SharePoint no disponemos de esta posibilidad de una forma trivial (al menos de momento) y tenemos que recurrir al desarrollo que, se nos complica porque nuestro objetivo incluye que la versión de SharePoint debe ser la 2013 online. Debido a estos “problemas”, hemos explorado diferentes medios por los cuáles alcanzar nuestro objetivo.

Primera opción

La primera de las opciones que evaluamos y, quizás la más lógica a priori, es el uso de un “Receptor remoto de eventos” (Remote Event Receiver) que es un nuevo elemento que trae SharePoint 2013 consigo y que consiste en un “servicio” que responde a los eventos que especifiquemos de una lista dentro de la app. Todo parecía ir genial, salvando ciertas complicaciones que se presentaron pero, finalmente descartamos esta opción porque nos fue imposible obtener el contexto (Context) del sitio de SharePoint desde el “Remote Event Receiver” y, era imprescindible que pudiéramos acceder a otra lista que contiene los usuarios/dispositivos a los que hay que enviar la “Push notification”.

Segunda opción

La segunda opción fue optar por LightSwitch, arriesgándonos al adentrarnos en terreno no habitual con la siguiente idea, crear una aplicación que recogiera las alertas, las propagara a la lista SharePoint y, además, leyera la lista de usuarios/dispositivos y les enviara la correspondiente Push Notification. Finalmente esta opción nos sirvió pero con algunos matices que explicaré más adelante.

 

Solución

El primer paso es crear nuestro proyecto de aplicación HTML de LightSwitch que usaremos para usar de pasarela entre SharePoint, sus listas y los dispositivos con Windows Phone de los usuarios.

LightSwitch-Project

 

Una vez se ha abierto el proyecto en blanco, deberíamos enlazar con la tabla de SharePoint online, peeeeero, es imposible realizar esta operación ya que SharePoint Online tiene problemas de autenticación con LightSwitch para esta acción, así que, procedemos a crear una tabla local a la aplicación de LightSwitch que llamaremos “Alerts” seleccionando la opción “Crear nueva tabla”

LightSwitch-Empty-Project

 

La tabla que he creado para las alertas contiendo los siguientes campos

  • Title: String
  • Body: String
  • DueDate: DateTime
  • AlertType: String (enumerado al que accedemos desde la opción “Choice List”)

LightSwitch-Add-Table

Ahora vamos a proceder a crear las páginas que necesitamos para nuestra aplicación, un listado de alertas que llamaremos BrowseAlerts y un formulario de edición llamado AddEditForm. Para ello hacemos click con el botón derecho del ratón sobre el nodo “Cliente” de la solución y seleccionamos “Añadir pantalla” (Add Screen).

Una vez se abra el selector de pantalla, seleccionamos el tipo “Browse Data Screen” para el listado de alertas y en Screen Data seleccionamos “AlertasSet” o el conjunto que corresponda con nuestra tabla.

image

 

Procedemos a realizar la misma operación para crear la pantalla de edición pero, esta vez seleccionamos “Add/Edit Details Screen” en el tipo de pantalla y “Alertas” en “Screen Data”.

image

 

Ahora tenemos que enlazar las pantallas para que desde el listado tengamos la opción de abrir el formulario y crear una nueva alerta. Para ello, abrimos la pantalla “BrowseAlerts” que representa al listado y seguir estas indicaciones:

  • En el árbol que veremos seleccionar el nodo “List”, lo que hará aparecer la opción “Añadir”.
  • Seleccionar “Añadir” y ponerle un nombre.
  • De la lista de opciones seleccionar “Añadir botón”.
  • De la ventana que se abre, seleccionar “Elegir un método existente” y en Navigate To seleccionar “Alert Form”

 

LightSwitch-Browse-Table-ItemsLightSwitch-Add-Button

 

Ahora que ya tenemos las pantallas enlazadas, tenemos que conectar nuestra aplicación con SharePoint. Para ello nos vamos a las propiedades del nodo del proyecto y en la sección SharePoint deberemos habilitar la conexión mediante el botón “Habilitar SharePoint”, lo que añadirá las referencias necesarias en nuestra aplicación para poder trabajar y, posteriormente deberemos poner la ruta de nuestro servidor.

LightSwitch-Enable-SharePoint

 

Por último, nos queda escribir el código necesario para que al crear una nueva alerta en la aplicación de LightSwitch, ésta se propague a la lista que le indiquemos de SharePoint. Para conseguirlo, debemos ir primero a la vista de código de la aplicación.

Toggle-View

 

Una vez tengamos la vista de código, en el nodo “Server” he creado una clase llamada “AlertHelper” que será la encargada de realizar la propagación del registro de la alerta.

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Web;

   5: using Microsoft.LightSwitch;

   6: using Microsoft.LightSwitch.Security.Server;

   7: using Microsoft.SharePoint.Client;

   8: using System.Linq.Expressions;

   9: using System.Net;

  10: using System.Text;

  11: using System.IO;

  12:  

  13: namespace LightSwitchApplication.Helpers

  14: {

  15:     public class AlertsHelper

  16:     {

  17:         public static bool AddAlert(Alert alert, ClientContext siteContext)

  18:         {

  19:             // Comprobamos el contexto del servidor de SharePoint

  20:             if (siteContext == null)

  21:                 throw new InvalidOperationException("Could not retrieve the Sharepoint context");

  22:  

  23:             // Obtener la lista

  24:             List alertsList = siteContext.Web.Lists.GetByTitle("Alerts");

  25:  

  26:             // Recordar que siempre hay que hacer un Load y un ExecuteQuery

  27:             siteContext.Load(alertsList);

  28:             siteContext.ExecuteQuery();

  29:  

  30:             try

  31:             {

  32:                 // Añadir la alerta a la lista

  33:                 var alertItem = alertsList.AddItem(new ListItemCreationInformation());

  34:                 alertItem["Title"] = alert.Title;

  35:                 alertItem["Body"] = alert.Body;

  36:                 alertItem["AlertType"] = alert.Type;

  37:                 alertItem["Expires"] = alert.DueDate;

  38:                 alertItem.Update();

  39:                 siteContext.ExecuteQuery();

  40:                 SendPushNotification(alert, siteContext);

  41:                 return true;

  42:             }

  43:             catch (Exception ex)

  44:             {

  45:                 return false;

  46:             }

  47:         }

  48:     }

  49: }

 

Ya sólo nos queda hacer que alguien llame al método de este “Helper”, y el encargado de hacerla será la clase “ApplicationDataService.cs” que se encuentra en la carpeta UserCode. Lo abrimos y le incluimos el método Alerts_Inserted que realizará la instancia del contexto del servidor de SharePoint y hará la llamada a la función del Helper que se encarga de propagar la alerta.

   1: public partial class ApplicationDataService

   2: {

   3:     partial void Alerts_Inserted(Alert entity)

   4:     {

   5:         var appWebContext = this.Application.SharePoint.GetHostWebClientContext();

   6:         var a = Helpers.AlertsHelper.AddAlert(entity, appWebContext);

   7:     }

   8:     

   9: }

 

Ahora ya lo tenemos todo listo y sólo nos queda ejecutar la aplicación y probar que funciona. Así es que le damos a F5, abriéndose así el navegador que nos pedirá autenticarnos en SharePoint y después nos mostrará una pantalla tal que así para “Confiar” en la aplicación que estamos desplegando. Seleccionamos “Trust It” para continuar.

SharePoint-Trust-Application

 

El siguiente paso nos lleva a la aplicación de alertas, mostrando la pantalla de listado con el botón para añadir alertas tal y como hemos diseñado.

LightSwitch-Application-Empty

 

Añadimos las alertas que queramos, en este caso he añadido 4 alertas para poder tener una visión de la aplicación con datos.

LightSwitch-Application-Form

 

Comprobamos en el listado que aparecen las alertas que vamos creando en la aplicación.LightSwitch-Application-List

 

Hasta aquí todo correcto pero… ¿qué ocurre con la lista de SharePoint? ¿Se han propagado los datos? Navegamos hasta ella y comprobamos que todo ha salido correctamente.

SharePoint-List

Espero que os sirva de ayuda. En el siguiente artículo completaré el proceso con el envío de las alertas a los dispositivos Windows Phone.

SharePoint 2010 | Obtener lista y añadir elementos desde un receptor de eventos (Event Receiver) de otra lista

Escenario:

Supongamos que tenemos una lista, llamémosla “fuente”, de SharePoint 2010 y queremos que al insertar o actualizar un elementos, se registre un log o un histórico en otra lista, llamémosla “destino”, es decir, insertar un registro en la otra lista con los datos que necesitemos. Para realizar esta operación deberíamos programar un EventReceiver y asignar nuestro código a los eventos deseado, ItemAdding, ItemAdded, ItemUpdating o ItemUpdated según sea el caso de nuestro escenario.

Solución

Tal y como ya avancé, tenemos que programar un EventReceiver asociado a la lista “fuente” y el evento deseado (Para el ejemplo he escogido ItemAdded), que se produce al insertar un nuevo registro. Lo que vamos a hacer es hacer una copia del registro insertado en la lista origen e insertarlo dentro de la lista destino.

   1: public override void ItemUpdated(SPItemEventProperties properties)

   2: {

   3:     // Obtener lista destino desde las propiedades del evento

   4:     SPList targetList = properties.Web.Lists["TargetList"];

   5:  

   6:     // Antes que nada, debemos comrobar si hemos conseguido obtener la lista 

   7:     if (targetList != null)

   8:     {

   9:         // Obtenemos el elemento que acabamos de insertar

  10:         SPListItem currentItem = properties.ListItem;

  11:  

  12:         // Instanciamos un nuevo elemento de la lista de destino

  13:         SPListItem targetItem = targetList.Items.Add();

  14:  

  15:         // Recorremos la lista de campos del elemento insertado para hacer una copia

  16:         foreach (SPField field in currentItem.Fields)

  17:         {

  18:             // Si la lista destino contiene el campo actual y el campo no es de sólo lectura

  19:             if (targetItem.Fields.Contains(field.Id) && !targetItem.Fields[field.Id].ReadOnlyField)

  20:             {

  21:                 // Establecemos el valor del campo

  22:                 targetItem[field.Id] = currentItem[field.Id];

  23:             }

  24:         }

  25:         // Se actualiza el registro en la lista para que los cambios tengan efecto

  26:         checkInItem.Update();

  27:     }

  28: }

 

Posible problema

Hasta aquí todo debería ir bien pero, ¿qué ocurre si no tenemos permisos en la lista destino? Por lo general un usuario estándar no debería tener permisos en el “histórico” de un proceso y lo que ocurre es que este código se ejecuta en nombre del usuario que realiza la operación, es decir, el usuario logueado en el sistema y, más aún, el parámetro SPItemEventProperties properties que recibe el evento está compuesto por los elementos para los que tiene permisos el usuario actual, con lo que la lista destino no estaría presente, con lo que no sólo no se podría insertar el elemento, sino que ni siquiera se podría obtener la lista destino.

 

Solución

La solución pasa por ejecutar el código mediante RunWithElevatedPrivileges y dentro del código instanciar tanto la colección de sitios como el sitio en cuestión de forma tradicional

   1: public override void ItemUpdated(SPItemEventProperties properties)

   2: {

   3:     // Comenzamos el bloque de ejecución con privilegios elevados

   4:     SPSecurity.RunWithElevatedPrivileges(delegate()

   5:     {

   6:         // Instanciar la colección de sitios con el Id que tenemos en properties 

   7:         using (SPSite mySite = new SPSite(properties.SiteId))

   8:         {

   9:             // Instanciar el sitio donde se encuentra la lista origen gracias a la URL que tenemos en properties

  10:             using (SPWeb myWeb = mySite.OpenWeb(properties.RelativeWebUrl))

  11:             {

  12:                 // Obtenemos la lista desde la colección de listas del sitio

  13:                 SPList checkInList = myWeb.Lists["TargetList"]; 

  14:             

  15:                 // Antes que nada, debemos comrobar si hemos conseguido obtener la lista 

  16:                 if (targetList != null)

  17:                 {

  18:                     // Obtenemos el elemento que acabamos de insertar

  19:                     SPListItem currentItem = properties.ListItem;

  20:             

  21:                     // Instanciamos un nuevo elemento de la lista de destino

  22:                     SPListItem targetItem = targetList.Items.Add();

  23:             

  24:                     // Recorremos la lista de campos del elemento insertado para hacer una copia

  25:                     foreach (SPField field in currentItem.Fields)

  26:                     {

  27:                         // Si la lista destino contiene el campo actual y el campo no es de sólo lectura

  28:                         if (targetItem.Fields.Contains(field.Id) && !targetItem.Fields[field.Id].ReadOnlyField)

  29:                         {

  30:                             // Establecemos el valor del campo

  31:                             targetItem[field.Id] = currentItem[field.Id];

  32:                         }

  33:                     }

  34:                     // Se actualiza el registro en la lista para que los cambios tengan efecto

  35:                     checkInItem.Update();

  36:                 }

  37:             }

  38:         }

  39:     });

  40: }

 

Como podéis ver, se instancian de una forma tradicional tanto la colección de sitios como el sitio donde se encuentran las listas. De esta forma, obtendremos esos elementos y sus propiedades dentro del contexto de privilegios elevados gracias a que se encuentran dentro del bloque RunWithElevatedPrivileges y por lo tanto, sí tendremos acceso a la lista destino. Finalmente, el resto del código es exactamente igual al inicial.

SharePoint 2010 | Ejecutar script tras la carga de la página ¿jQuery document ready o _spBodyOnLoadFunctionNames?

Escenario:

Necesitamos ejecutar cierto código Javascript pero queremos que se haga al final de la carga de la página, por ejemplo si vamos a rellenar un input que no sabemos en qué momento estará disponible.

Solución jQuery:

Por todos es sabido a estas alturas que el problema se resolvería fácilmente haciendo uso de jQuery controlando el momento en el que la página esté “lista (ready)”, es decir:

   1: $(document).ready(function() {

   2:    // Código a ejecutar

   3:    // ...

   4: });

Pero estamos hablando de SharePoint 2010 que usa bastante Javascript para realizar acciones de carga o de control de los campos atendiendo a su tipo. Por lo tanto, ¿podemos asegurar que la página esté “lista (ready)” y que todo esté terminado de cargar cuando se ejecute  $(document).ready(…)? Pues… aunque cueste creerlo, la respuesta es que no. SharePoint sigue haciendo algo de carga en algunos casos y, aunque como norma general no deberíamos tener problemas, podemos encontrarnos alguna situación en la que no funciona como debería.

Solución _spBodyOnLoadFunctionNames:

SharePoint utiliza sus propias funciones de carga y, en este caso vamos a aprovechar la función que se ejecuta en la carga del body, _spBodyOnLoadFunctionNames que se conjuntará con el código que usemos en el caso anterior. Para ello, sólo tendremos que hacer algo muy sencillo como es encapsular dentro de una función el código que queremos ejecutar al finalizar la carga de la página e instanciarlo con _spBodyOnLoadFunctionNames que lo pondrá en una cola de carga de scripts y que se ejecutar al finalizar todos los procesos de SharePoint

   1: _spBodyOnLoadFunctionNames.push("myCustomFunctionName");

   2:  

   3: function myCustomFunctionName() {

   4:    // Código a ejecutar

   5:    // ...

   6: }

 

Conclusión:

Es importante que intentemos hacer uso de las funciones que SharePoint nos provee y aprovechar así que la rueda ya está inventada, en vez de como casi siempre hacemos los amantes del desarrollo que es hacer nuestro propio código porque lo vemos más claro y, en ocasiones, incluso mejor. Un error que cometemos muy a menudo.

Compartimos, la revista digital de SharePoint en castellano estrena portal web en SharePoint 2013

Hace ya algún tiempo, aprovechamos el lanzamiento público de Windows 8 por parte de Microsoft para presentar la correspondiente aplicación de CompartiMOSS en la que tuve el gusto de colaborar. Sin duda, fue un rotundo éxito que nos hizo pensar más allá y proponer un rediseño de la revista para ayudar a los lectores a encontrar los contenidos que buscan. Por lo tanto, el siguiente paso que debíamos dar era diseñar un nuevo portal web que permitiera consumir los artículos individualmente, obtener información de los editores y, sobre todo que otros usuarios que aún no conocen la revista puedan encontrarla fácilmente desde los buscadores.

Una vez teníamos la idea en la mente, el siguiente paso me correspondió para presentar una propuesta de diseño que gustó a los directores de la revista y que se decidió implantar en SharePoint 2013, habéis leído bien, usamos la nueva versión de la plataforma de Microsoft, con lo que comenzó un divertido camino que me permitió jugar con las diferentes y nuevas opciones disponibles en SharePoint 2013 para aplicar el diseño del portal desde la creación de una Masterpage (página maestra) y los distintos Page Layouts (Plantillas de página) hasta los Display Templates (Plantillas para mostrar). Todo ello además, intentando hacer el máximo uso de HTML5, CSS3 y Javascript conjugando las nuevas tecnologías a nuestro alcance en materia de entornos web.

Al tiempo que aplicaba el Branding al sitio de SharePoint 2013, Alberto Díaz configuraba todo lo necesario para que el funcionamiento fuera el deseado y, además también insertaba los contenidos provistos por los directores Juan Carlos González, Gustavo Vélez y Fabián Imaz que trabajaban a un ritmo frenético para tenerlo todo listo. Finalmente, nos dio tiempo de lanzar el nuevo portal como regalo de reyes el día 6 de enero estrenando además el nuevo número de la revista en el que, además tuve el honor de escribir un artículo sobre la aplicación de Windows 8 de CompartiMOSS. El resultado podéis evaluarlo y opinar. Espero que os guste

Nuevo número de CompartiMOSS

compartimos-numero-14

Aplicación de Windows 8 de CompartiMOSS

CompartiMOSS-Windows8

Nuevo portal web de Com0partiMOSS

CompartiMOSS-Web

Antes de irme, me gustaría deciros que estéis atentos a las próximas novedades porque estamos que lo tiramos y pronto daremos nuevas sorpresas.

Javascript | Cómo cargar jQuery y cualquier script dinámicamente

Escenario:

Supongamos que queremos cargar jQuery sólo cuando lo necesitamos, por ejemplo, si tenemos un Control de usuario, o una librería de funciones que hace uso de jQuery y no queremos depender de si el portal web en el que lo queremos incrustar ya ha realizado la carga de esta librería de javascript.

Solución:

Aunque es algo bastante sencillo, siempre tengo que buscarlo y cada vez que lo hago me encuentro soluciones “estrambóticas” que en vez de facilitar la vida, la complican más aún. Por eso, quería contribuir con la solución más eficaz a esta cuestión.

Comprobar si jQuery está cargado en nuestra página

Con un sencillo bloque condicional, podemos comprobar si jQuery está presente en nuestro entorno.

   1: if(jQuery) {

   2:    alert('jQuery está cargado');

   3: } else {

   4:    alert ('jQuery NO está cargado');

   5: }

 

Cargar jQuery dinámicamente

Haciendo uso de Javascript, cargaremos la librería jQuery de forma dinámica en el caso de que no estuviera presente en el sistema. Para ello, modificamos un poco el bloque condicional anterior para quedarnos únicamente con la opción en caso de que no estuviera cargado jQuery previamente

   1: if (!jQuery)

   2: {

   3:     (function(){

   4:       var newscript = document.createElement('script');

   5:          newscript.type = 'text/javascript';

   6:          newscript.async = true;

   7:          newscript.src = 'http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.min.js';

   8:       (document.getElementsByTagName('head')[0]||document.getElementsByTagName('body')[0]).appendChild(newscript);

   9:     })();

  10: }

  11:  

 

Comprobar versión de jQuery

Si además necesitáramos comprobar que la versión de jQuery sea una específica o superior, podemos hacer uso de esta simple función.

   1: function CheckJQueryVersion(minimalVersion) {

   2:     // get version as a string and get rid of the periods. 

   3:     version = jQuery.fn.jquery.split('.').join('');

   4:     version2Check = minimalVersion.split('.').join('');

   5:     

   6:     version = parseInt(version);

   7:     if(version >= version2Check){

   8:         alert("Using version " + minimalVersion + " or greater");

   9:         return true;

  10:     }else{

  11:         alert("jQuery version is lower than " + minimalVersion);

  12:         return false;

  13:     }

  14: }

 

 

Espero que os sirva de ayuda, sobre todo ahora que el mundo web gira de forma esencial en torno a Javascript.

2013, un nuevo año con muchas expectativas

Tras unas largas vacaciones y el período de vuelta al trabajo, vuelvo a la carga con el blog cargado de artículos que me parecen interesantes sobre las tecnologías de Microsoft con las que trabajo habitualmente. Así pues, una vez terminado un año 2012 cargado de participaciones en eventos de desarrollo o muy relacionados con este mundo, como la Tenerife Lan Party 2k12 (TLP2k12), el Megathon de Windows 8 y el Lanzamiento de Visual Studio 2012 entre otros y en los que he compartido muchos buenos momentos con los asistentes que me han ayudado a crecer, uno de mis propósitos para este nuevo año en el que hemos entrado y que tiene muy mala rima es el de consolidar mi participación en eventos junto a TenerifeDev y General de Software y seguir mejorando día a día gracias al gran “coach” que es Alberto Díaz y a los pedacitos de sabiduría que voy recogiendo de otros grandes colaboradores de la comunidad de desarrolladores.

Además, este año se presenta cargado de trabajo (y eso que acabamos de empezarlo) debido a la actualización de productos y tecnologías de Microsoft, sobre todo la incorporación de HTML5 con Windows 8 y SharePoint 2013, por lo que escribiré bastante a menudo sobre Javascript agggggg $##@@~$%, ese gran lenguaje rescatado de la ultratumba Risa , con lo que espero poder aportar mi granito de arena y ayudar a aquellos que buscan información en la red para resolver dudas o encontrar trucos que den respuesta a sus inquietudes.

Bueno, no me extenderé más en este artículo y, sin más preámbulos, doy el pistoletazo de salida a este año 2013

Windows 8 Store Apps | Usar Extended Splash Screen para cargas de datos iniciales

En Windows 8, la gran mayoría de las aplicaciones se alimentan de contenido en internet y, por ello, deben hacer cargas de datos iniciales desde la red, como en aplicaciones de noticias, que podemos gestionar de diferentes formas más o menos elegantes.

  • Abrir la aplicación vacía de datos y, en la página principal realizar la carga de contenido desde internet.

    En este caso, se mostraría al usuario una página inicial "vacía" y se debería notificar al usuario que se están cargando los datos que, en muchos casos no deberían ser mostrados hasta la finalización de la carga de los mismos. Esto produciría un efecto muy feo de "Vacío-Lleno" además de que en las guías de diseño que ha realizado Microsoft, no se recomienda esta opción porque no da buena imagen mostrar la aplicación en su "esqueleto".

    image

     

  • Abrir la aplicación con datos almacenados de anteriores ejecuciones, es decir, datos antiguos "cacheados".

    Presenta un paradigma similar al anterior en el que, al mostrar la página inicial al usuario, habría que notificarle que se están cargando los datos pero, tendremos un problema mayor, dado que mientras se cargan los datos actuales el usuario podría interactuar con los datos antiguos, lo que podría provocar conflictos en la mayoría de los casos porque estará accediendo a las colecciones de datos mientras éstas se están actualizando. Una opción para salvar este problema sería bloquear la pantalla al usuario pero volvemos a entrar en conflicto con las recomendaciones que Microsoft indica en sus guías de diseño que, además, indican que no se debe bloquear la pantalla al usuario salvo necesidad imperativa.

    image

     

  • Extender la Splash Screen para realizar la carga de datos.

    Finalmente, la opción más elegante que además nos permitirá iniciar la aplicación datos y que éstos además sean los actuales, es extender la Splash Screen de nuestra aplicación mediante una "Extended Splash Screen" y que sea esta la que se encargue de cargar los datos a la vez que notifica al usuario el proceso. De esta forma, al terminar la carga de datos, la aplicación presentaría la página inicial de la aplicación al usuario con los datos actuales.

Extended-Splash-Screen

 

Una vez que tenemos claro que la mejor opción y la más elegante es el uso de una "Extended Splash Screen", tenemos que programarla correctamente, lo que no es algo trivial y que requiere editar más archivos de lo que a priori parecería.

Paso 1: Crear una nueva vista que he llamado ExtendedSplash y que servirá para realizar la carga de los datos. Esta vista sólo debe contener este "Grid" en el código XAML y no ser parte de una etiqueta "<Page>" ni "<commo:LayoutAwarePage>", es decir, al crearla, eliminamos todo el contenido XAML que contiene y ponemos este Grid que contiene, la imagen de SplashScreen que deberá ser puesta tal cual aparece en el ejemplo para que no haya diferencia con la vista anterior y además, he añadido otro Grid con un "ProgressRing" que indicará que hay un proceso en ejecución y un "TextBlock" con el texto "Cargando datos". Estos dos últimos elementos sí pueden ser modificados a nuestro gusto.

<Grid Background="#FFFFFFFF"
      x:Class="ExtendedSplashScreen.Views.ExtendedSplash"
      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="1366" d:DesignHeight="768">
    
    <Image x:Name="extendedSplashImage" 
           Source="ms-appx:///Assets/SplashScreen.png" 
           Height="300" 
           Width="620" 
           VerticalAlignment="Center" 
           HorizontalAlignment="Center" />
    <Grid VerticalAlignment="Center" 
          HorizontalAlignment="Center" 
          Margin="0,300,0,0">
        <ProgressRing x:Name="ProgressRing" 
    		Foreground="#FF00529f" 
    		IsActive="True" 
    		Width="80" 
    		Height="80"
    		VerticalAlignment="Center"
    		HorizontalAlignment="Center"/>
        <TextBlock Text="Cargando datos..." 
                   FontSize="20" 
                   VerticalAlignment="Center" 
                   HorizontalAlignment="Center" 
                   Padding="0,20,0,0" 
                   Foreground="#FF00529F" 
                   Margin="0,40,0,-60"/>
    </Grid>
</Grid>

 

Paso 2: Una vez tengamos la vista creada, debemos indicarle a la aplicación que la navegación inicial la haga hacia nuestra Extended Splash Screen y no a la vista principal de la aplicación que teníamos anteriormente. Para ello debemos identificar el bloque condicional if (rootFrame.Content == null) y ponerlo como indico a continuación.

if (rootFrame.Content == null)
{
    bool loadState = (args.PreviousExecutionState == ApplicationExecutionState.Terminated);
    ExtendedSplash extendedSplash = new ExtendedSplash(args.SplashScreen, loadState);
    Window.Current.Content = extendedSplash;
}

 

Paso 3: En este momento, nuestra aplicación ya será capaz de navegar a la Extended Splash Screen pero ésta de momento no hace nada, por lo que es hora de añadir el código necesario para la carga de los datos y que posteriormente continúe con la ejecución de la aplicación de forma normal en la que queremos que sea la vista inicial de nuestra aplicación. Para ello, el archivo de Code Behind debería quedar similar al ejemplo que sigue.

    partial class ExtendedSplash
    {
        internal Rect splashImageRect; // Almacena las coordenadas de la imagen.
        internal bool dismissed = false; // Control del estado de finalización.
        internal Frame rootFrame;
        private SplashScreen splash; // Variable to hold the splash screen object.

        public ExtendedSplash(SplashScreen splashscreen, bool loadState)
        {
            InitializeComponent();

            // Escucha los eventos de redimensionamiento de la vista para reposicionar la Extended Splash Screen
            // Importante para asegurarnos que la vista responde bien ante los diferentes estados (Snapped, Portrait, Fill)
            Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);

            splash = splashscreen;

            if (splash != null)
            {
                // Registra un manejador de eventos que se ejecutará cuando la SplashScreen haya sido finalizada
                splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);

                // Recupera las coordenadas de la imagen
                splashImageRect = splash.ImageLocation;
            }

            // Se crea un frame que actúa como context de naveigación 
            rootFrame = Window.Current.Content as Frame;

            // Recupera la session guardada si es necesario
            RestoreStateAsync(loadState);

        }

        async void RestoreStateAsync(bool loadState)
        {
            if (loadState)
                await SuspensionManager.RestoreAsync();
        }

        void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
        {
            // Actualiza las coordenadas de la imagen Splash Screen de forma segura.
	     // Este evento será lanzado para responder a los cambios de estado Snap, Rotación, etc.
            if (splash != null)
            {
                // Actualiza la imagen de Splash Screen.
                splashImageRect = splash.ImageLocation;
            }
        }

        // Incluye el código a ejecutar cuando el Sistema haya transicionado desde la Splash Screen hasta la Extended.
        async void DismissedEventHandler(SplashScreen sender, object e)
        {
            // Se inicia el proceso de carga de datos
            await LoadData();

            // Navegar desde la Extended Splash Screen hasta la página principal de la aplicación
            await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                rootFrame.Navigate(typeof(GroupedItemsPage));

                // Se establece el estado de la Extended Splash Screen en la página principal de la aplicación
                ((GroupedItemsPage)rootFrame.Content).SetExtendedSplashInfo(dismissed);
	
                // Se coloca el frame en la ventana actual
                Window.Current.Content = rootFrame;
            });
        }

        /// <summary>
        /// En esta función se cargan los datos de la aplicación
        /// </summary>
        /// <returns></returns>
        private async Task LoadData()
        {
            App.SampleDataGroup = SampleDataSource.GetGroups(AllGroups);
            dismissed = true;
        }
    }


Para que no extrañéis y por comodidad para el ejemplo, he establecido una propiedad estática en App.xaml.cs llamada App.SampleDataGroup donde almaceno los datos que he cargado para que puedan ser usados posteriormente en la vista principal de la aplicación. Si siguiéramos una estructura MVVM estricta esto se debería resolver con buenas artes.

 

Paso 4: Ya nos encontramos en el último paso del proceso de carga de datos que, por fin es mostrárselos al usuario y, para esto, tenemos que cambiar unas poquitas cosas en la vista principal de la aplicación. Lo primero es declarar una variable "Dismissed" y un método público para establecer su valor. Si os habéis fijado con detenimiento, os daréis cuenta que este método se usa en la Extended Splash Screen para notificar su finalización de carga. En principio no es necesario hacer nada con esta variable, pero podría sernos de utilidad en algunos casos.

        internal bool Dismissed;

        public void SetExtendedSplashInfo(bool dismissStat)
        {
            Dismissed = dismissStat;
        }

 

En Segundo lugar, los datos ya no se van a cargar en la vista principal, sino que cuando la aplicación llegue aquí, los datos ya deberían estar cargados donde hayamos indicado y, en este caso, yo lo he almacenado por comodidad en App.SampleDataGroup, por lo que el evento LoadState de esta vista quedaría así.

 

        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            this.DefaultViewModel["Groups"] = App.SampleDataGroup;
        }

 

 

Conclusión: Tal y como nos recomienda Microsoft, las aplicaciones tienen que ofrecer los datos lo más rápidamente posible o, al menos, notificar que se están obteniendo dado que nuestras aplicaciones deben ser "Fast & Fluid". Con las Extended Splash Screens podemos paliar el efecto de carga de datos permitiendo que el usuario sea consciente del proceso que se está ejecutando. Además, es importante tener en cuenta que si nuestras aplicaciones superan los 5 segundos pausadas en la SplashScreen por defecto, porque estemos haciendo carga de datos, Microsoft no nos va a certificar la aplicación por falta de rendimiento, por lo que en esos caso, el uso de una Extended Splash Screen se hace absolutamente necesario.

 

Podéis descargaros una aplicación que hace uso de la plantilla "Aplicación de cuadrícula (Grid App)" con el código de ejemplo para verlo en ejecución.

download

TechDay y CommunityDay 2012: “Sophomore” en el evento de comunidad de Microsoft

Por segundo vez consecutiva he tenido la suerte de ser invitado al evento de comunidad que Microsoft organiza cada año y, en el que se reúnen MVP’s (Most Valuable Professionals) de todas las tecnologías junto con otros miembros de otros niveles como MSP’s (Microsoft Student Partners) y Technical Rangers entre los que me incluyo.

En esta ocasión, el evento fue más corto e intenso que el año anterior y, por lo que he oído, también con respecto a otros años, pero no por ello ha sido de menor calidad, es más, gracias a que se compartía fecha con el TechDay, pudimos disfrutar de un gran encuentro con más gente de la esperada y realizar más “NetWorking” que nunca.

 

La llegada

Al llegar al Teatro Goya de Madrid recibimos la primera sorpresa, una banda amenizaba en vivo nuestra entrada a la sala en la que reinaba una gran proyección del TechDay

TechDay

 

Apertura del evento

El grupo de evangelistas de Microsoft realizó una gran puesta en escena muy amena, interesante y, sobre todo, muy cercana a nosotros con un Jose Bonnin que parecía querer hipnotizarnos con su tono familiar mientras no paraba de echar piropos a la comunidad de profesionales que trabajan con tecnologías Microsoft y, sobre todo, a los que colaboramos con nuestro granito de arena para hacer más fácil el trabajo con éstas o su aprendizaje.

TechDayApertura

Las charlas

Pudimos asistir a charlas de gran calidad y profundidad en sesiones paralelas para ITPro’s y Desarrolladores entre las que destacaría la ofrecida por Alberto Díaz y a algunos Showman’s que nos animaron con sus charlas el duro día que tuvimos desde las 10.00 de la mañana hasta las 17.00.

Alberto-Diaz

El CommunityDay

Un poco o “muy mucho” descafeinado con respecto a lo que viví el año pasado. Se destacó por el bautizo, con el “Responsable Oficial”, de una gran cantidad de nuevos MVP’s, de los MSP’s y el rebautizo de algún infiltrado espontáneo que junto a la ausencia de “Peris” fue parte común de este tramo del evento. Después, comienza el “Networking” de nuevo, pero esta vez las conversaciones y las opiniones son más profundas.

CommunityDay

El día siguiente

Microsoft nos tenía preparada una gran sorpresa que consistía en una “Gincana por Madrid”. Con el fin de ayudarnos a conocer la ciudad y para divertirnos un rato compitiendo entre nosotros dejando de lado por un momento la tecnología (o no tanto), todos los asistentes al evento, evangelistas incluidos, recorrimos las calles de Madrid en busca de fotos, objetos y respuestas para sumar el mayor número de puntos posibles. Para ello, sólo contábamos con una cámara de fotos “Polaroid”, un mapa y el libro de ruta.

CommunityDay-Next-Day

El resumen

Una vez más, creo que Microsoft ha organizado un evento enriquecedor y divertido que a buen seguro nos hace recargar las pilas para seguir colaborando con la comunidad de profesionales, estudiantes, investigadores, etc. que hacen uso de tecnologías con la firma de la compañía de Redmond.

 

Mil gracias por esta segunda invitación.

[Evento] Resumen del lanzamiento de Visual Studio 2012 con TenerifeDev

El pasado 9 de noviembre, tuve la suerte de participar en el evento de Lanzamiento de Visual Studio 2012 organizado por TenerifeDev, grupo de usuarios de .Net de Tenerife con el que participo. El evento tuvo una excelente acogida por parte de los profesionales de la isla interesados en conocer las novedades de la nueva versión del IDE de Microsoft, tanto es así que las plazas se agotaron en muy pocos días, ¡todo un hito en la isla!

La jornada, comenzó con la apertura de Alberto Díaz que continuó con su primera charla “Novedades de Visual Studio 2012” en la que mostró a todos los asistentes las nuevas posibilidades que Microsoft ha dispuesto en la nueva versión de su IDE.

Tras conocer las novedades de Visual Studio 2012, entramos un poco en materia de qué podemos hacer con ellas y, David Rodríguez y César Abreu dieron a conocer “WebAPI”, sin duda una gran ayuda para los desarrolladores.

 

A continuación Sergio Marrero se estrenó como ponente junto a TenerifeDev para hablarnos de “async/await” que nos ayudará a hacer nuestro código más legible y limpio.

 

De nuevo, Alberto Díaz intervino para presentarnos todo lo referente al desarrollo de aplicaciones para Windows Phone 8, destacando el emulador que se ejecuta sobre una máquina virtual con Hyper-V

 

Finalmente, me tocó a mi realizar el cierre de la jornada hablando sobre las Windows Store Apps, sesión durante la que resalté la gran oportunidad que se nos presenta a los desarrolladores al tener un nuevo mercado de escala mundial al alcance de nuestros “teclados y ratones”

 

En resumen, fue un gran evento marcado por el gran seguimiento que tuvimos y que nos anima a seguir realizando esta labor de difundir en Tenerife las nuevas tendencias tecnológicas así como nuestros conocimientos. Desde TenerifeDev, os animamos a proponer nuevos temas sobre los que os interese aprender y, sobre todo, participad con nosotros. Muchas gracias a todos los asistentes y a la Fundación Empresa de la Universidad de La Laguna (FEULL) por colaborar una vez más con TenerifeDev.

[Evento] Lanzamiento de Visual Studio 2012 con TenerifeDev

Después del gran despliegue que hicimos en TenerifeDev con la organización del Megathon de Windows 8 en Tenerife, mucho estábamos tardando en volver a tirar la casa por la ventana. En esta ocasión, queremos contribuir a que los usuarios descubran Visual Studio 2012 y las grandes novedades que trae consigo.

Para ello, en TenerifeDev nos hemos puesto manos a la obra para, el día 9 de noviembre, ofrecer unas sesiones gratuitas en forma de “píldoras” para que los usuarios puedan descubrir nuevas experiencias en el desarrollo de aplicaciones mediante el uso de Visual Studio 2012, más rápido, más potente, mejor depuración, más plantillas de aplicaciones y, sobre todo, la posibilidad de crear aplicaciones para la Windows Store con estilo Modern UI, antiguamente conocido como estilo Metro.

En esta ocasión me encargaré de lanzar la píldora sobre Windows Store Apps en la que hablaré de los diferentes tipos de plantilla existentes tanto para Silverlight como para HTML5 que nos permiten crear aplicaciones de estilo Modern UI que se podrán publicar posteriormente en la Windows Store.

No os podéis perder esta oportunidad recibir formación, como siempre gratuita gracias a TenerifeDev, de manos Alberto Díaz, MVP de SharePoint, David Rodríguez, experto en DotNetNuke y Azure, Sergio Marrero y yo mismo. Registraros cuanto antes que las plazas son limitadas.

 

Datos del evento

Fecha: 9 de noviembre de 2012

Lugar: Aulas de la Fundación de Empresa Universidad de la La Laguna (FEULL)

Hora: De 17:00 a 20.00

Registro: Enlace

 

 

Agenda

Novedades de Visual Studio 2012 con Alberto Díaz 

WebAPI con David Rodríguez y César Abreu  

Async/Await con Sergio Marrero 

Windows Phone con Alberto Díaz 

Windows Store Apps con Santiago Porras

Programa