Comunidad de diseño web y desarrollo en internet online

Tutorial de desarrollo de aplicaciones para Windows Phone 7

Este es el primer artículo de una serie dedicada al desarrollo de aplicaciones para Windows Phone 7 en Silverlight. Como primer ejemplo vamos a crear una aplicación sencilla de representación de datos y la iremos refinando en sucesivos episodios:

  1. Aplicación base: representación de datos y visionado de vídeos.
  2. Mejoras visuales y navegación
  3. Guardar el estado (tombstoning)
  4. Mejoras de rendimiento
  5. Interacción con otros servicios
  6. Preparación para el Marketplace

Veremos lo fácil que nos va a resultar realizar la primera versión mientras que el aspecto de la aplicación va a resultar profesional desde el primer momento. Una característica común de las aplicaciones WP7.

Plantillas de proyecto para WP7


Cuando creamos una aplicación en Silverlight para Windows Phone 7 tenemos varias proyectos base donde elegir:
  1. Aplicación Windows Phone: nos da una pantalla con un título donde podemos empezar a crear nuestra aplicación desde cero. Aunque sea la primera opción que tenemos es la más cruda de todas, yo recomiendo no empezar por aquí.
  2. Una aplicación conectada a datos: en este caso nos proporcionan dos pantallas, una principal y otra de detalle. Es conectada a datos al modo de WP7, es decir, no esperéis un sql compact o algo parecido, WP7 está pensado para consumir datos de la nube, así que los datos se obtendrán inicialmente a través de la conexión de red.
  3. Un Panorama: que nos permite crear una aplicación que ocupa una región más grande que la pantalla con una imagen de fondo común. Es el proyecto más vistoso de todos y el que se suele usar de base para casi todas las aplicaciones básicas del WP7: contactos, imágenes, marketplace, etc….
  4. Un Pivot: la versión WP7 de lo que sería una página con tabs, se usa por ejemplo para el cliente de correo o para las pantallas de configuración.

La aplicación


La idea es crear una aplicación que nos de una vista de noticias, artículos y vídeos recientes, tal como sería para un canal de noticias cualquiera. Para el ejemplo voy a usar las fuentes RSS que hay en MSDN España y así estaremos al día en últimas tecnologías.

Para ello vamos a crear una aplicación tipo Panorama, pues es la más adecuada ya que nos da un patrón de diferentes vistas conectadas a una fuente de datos. Vamos a empezar creando un nuevo proyecto del tipo "Windows Phone Panorama Application"


La plantilla nos creará un proyecto con datos de ejemplo para que veamos en la lista de diseño cómo quedará la aplicación. El esquema de los datos está definido como la clase ItemViewModel dentro de la carpeta ViewModels y también tenemos el MainViewModel donde tenemos la colección de datos que vamos a mostrar.

Dentro del proyecto que nos crea la plantilla Panorama tenemos ejemplos de cómo representar los datos, la manera más sencilla: una listbox que enlazaremos a la colección de datos que tenemos en el ViewModel.

Para nuestro caso vamos a borrar ItemViewModel generado, pues vamos a crear nuestras propias clases para representar las fuentes RSS y borraremos el contenido de MainViewModel, donde luego escribiremos el código para recuperar los datos. Las fuentes de datos que vamos a utilizar son fuentes disponibles públicamente. Son las mismas que podemos usar desde cualquier lector de feeds o como fuente de datos para nuestros mashups. Para el ejemplo, como ya he dicho antes, usaremos las fuentes de MSDN España, una de vídeos y otras dos de texto:
Para poder utilizar el contenido de las fuentes necesitaremos abrir una conexión web, leer el contenido xml del feed y rellenar una lista que nos sirva de fuente para la Listbox. Vamos allá: Primero crearemos las clases que necesitamos para representar los elementos de la lista:

Código :

public class ElementoEntradaVideo
{
    /// <summary>
    /// Namespace usado para encontrar el namespace "media:"
    /// </summary>
    public static XNamespace Media="http://search.yahoo.com/mrss/";
    public string Title { get; set; }
    public string Video { get; set; }
    public string Description { get; set; }
    public string Thumbnail { get; set; }
    public static List<ElementoEntradaVideo> GetElements(string response)
    {
        List<ElementoEntradaVideo> elementos=new List<ElementoEntradaVideo>();
        var rssFeed= XElement.Parse(response);
        var channel=rssFeed.Descendants("channel");
        
        elementos=(from item in channel.Elements("item")
                     select new ElementoEntradaVideo
                     {
                         Title=item.Element("title").Value,
                         Description=item.Element("description").Value,
                         Video=item.Element("enclosure") == null ? null :
                            item.Element("enclosure").Attribute("url").Value,
                         Thumbnail =
                             (from thumb in item.Descendants(Media + "thumbnail")
                              orderby int.Parse(thumb.Attribute("width").Value)
                              select thumb.Attribute("url").Value).FirstOrDefault()
                     }).ToList();
        return elementos;
    }
}

El método GetElements interpreta el xml y crea una lista de elementos que usaremos parar rellenar las listas que mantendremos en el MainViewModel.

En el MainViewModel vamos a crear tres coleciones, del tipo ObservableCollection, que contendrán los datos a mostrar:

Código :

public class MainViewModel : ViewModelBase
{
    public const string _spain="http://channel9.msdn.com/Blogs/channel9spain/RSS";
    public const string _noticiasLink="http://www.microsoft.com/spain/msdn/rss/noticias.xml";
    public const string _articulosLink="http://www.microsoft.com/spain/msdn/rss/articulos.xml";


    public MainViewModel()
    {
        Videos=new ObservableCollection<ElementoEntradaVideo>();
        Noticias=new ObservableCollection<ElementoEntradaRss>();
        Articulos=new ObservableCollection<ElementoEntradaRss>();
    }


    public ObservableCollection<ElementoEntradaVideo> Videos
    {
        get;
        private set;
    }

    public ObservableCollection<ElementoEntradaRss> Noticias
    {
        get;
        private set;
    }

    public ObservableCollection<ElementoEntradaRss> Articulos
    {
        get;
        private set;
    }

Dentro del MainViewModel abriremos un WebClient para solicitar el contenido de la fuente rss y cuando lo recibamos usaremos el método GetElements para obtener la colección:

Código :

private void fillVideos(string rssUrl)
{
    WebClient client=new WebClient();
    client.DownloadStringCompleted += (x, e) =>
    {
        if (e.Error == null)
        {
            List<ElementoEntradaVideo> elements=ElementoEntradaVideo.GetElements(e.Result);
            elements.ForEach((element) => this.Videos.Add(element));
        }
    };
    client.DownloadStringAsync(
        new Uri(rssUrl));
}

El método DownloadStringAsync ejecuta una llamada asíncrona al servidor de la fuente rss que se vuelve a sincronizar con el UI en el método DownloadStringCompleted. Sobre esta llamada y sobre cómo mejorar el rendimiento cuando hacemos llamadas remotas hablaremos en el capítulo 4 de esta serie.

Para que todo esto funcione debemos cargar los datos desde la vista XAML, así en el codebehind tendremos que llamar al método de carga del MainViewModel:

Código :

// Constructor
public MainPage()
{
    InitializeComponent();

    // Set the data context of the listbox control to the sample data
    DataContext=App.ViewModel;
    this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}

// Load data for the ViewModel Items
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    App.ViewModel.LoadData();
}

Diseño del UI


Ahora nos toca ya diseñar el aspecto del interfaz gráfico, lo primero que vamos a hacer es rellenar el fichero de datos de ejemplo para poder ver en el diseñador cómo nos queda.

Código :

<local:MainViewModel
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CanalDeNoticiasMSDN.ViewModels">
    
    <local:MainViewModel.Videos>
        <local:ElementoEntradaVideo Title="Título 1"/>
        <local:ElementoEntradaVideo Title="Título 2"/>
        <local:ElementoEntradaVideo Title="Título 3"/>
        <local:ElementoEntradaVideo Title="Título 4"/>
        <local:ElementoEntradaVideo Title="Título 5"/>
        <local:ElementoEntradaVideo Title="Título 6"/>
    </local:MainViewModel.Videos>
    <local:MainViewModel.Noticias>
        <local:ElementoEntradaRss Guid="1" Title="Título 1" Description="Descripción del título 1" PubDate ="1/1/2010 14:04:05"/>
        <local:ElementoEntradaRss Guid="2" Title="Título 2" Description="Descripción del título 1" PubDate ="1/1/2010 14:04:05"/>
        <local:ElementoEntradaRss Guid="3" Title="Título 3" Description="Descripción del título 1" PubDate ="1/1/2010 14:04:05"/>
    </local:MainViewModel.Noticias>
    <local:MainViewModel.Articulos>
        <local:ElementoEntradaRss Guid="1" Title="Título 1" Description="Descripción del título 1" PubDate ="1/1/2010 14:04:05"/>
        <local:ElementoEntradaRss Guid="2" Title="Título 2" Description="Descripción del título 2" PubDate ="1/1/2010 14:04:05"/>
        <local:ElementoEntradaRss Guid="3" Title="Título 3" Description="Descripción del título 3" PubDate ="1/1/2010 14:04:05"/>
    </local:MainViewModel.Articulos>

</local:MainViewModel>

Una vez rellenados los datos abrimos MainPage.xaml y creamos el primer PanoramaItem para representar los vídeos:

Código :

<!--Panorama item one-->
<controls:PanoramaItem Header="Vídeos">
    <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Videos}"
             SelectionChanged="ListBox_SelectionChanged">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
                    <Image Height="100" Width="100" Source="{Binding Thumbnail}"
                           Margin="12,0,9,0"/>
                    <StackPanel Width="311">
                        <TextBlock Text="{Binding Title}" TextWrapping="Wrap"
                                   Style="{StaticResource PhoneTextTitle3Style}"/>
                    </StackPanel>
                </StackPanel>
             </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</controls:PanoramaItem>

Dentro del PanoramaItem tenemos una ListBox, enlazamos la propiedad ItemSource a la lista llamada Videos que hemos creado antes. Dentro de la listbox modificamos el DataTemplate para poner la imagen y el título y ya tenemos una bonita lista que incluye un fotograma y un título por cada entrada. El control ListBox se encargará de repetir el patrón, hacer scroll de los elementos y de la interacción con el usuario.

Para los artículos y las noticias es bastante parecido.

Código :

<!--Panorama item two-->
<controls:PanoramaItem Header="Artículos">
     <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Articulos}"
              SelectionChanged="ListBox_SelectionChanged_1">
         <ListBox.ItemTemplate>
             <DataTemplate>
                 <StackPanel Margin="0,0,0,17">
                         <TextBlock Text="{Binding Title}"
                                    TextWrapping="Wrap"
                                    Style="{StaticResource PhoneTextTitle2Style}"/>
                     <TextBlock Text="{Binding PubDate}"/>
                 </StackPanel>
             </DataTemplate>
         </ListBox.ItemTemplate>
     </ListBox>
</controls:PanoramaItem>

Al ejecutar la aplicación ya podremos ver el resultado:


Visualización de los datos


Ahora que la aplicación ya muestra el título de las entradas e incluso las imágenes ¿Cómo vemos el contenido al que apuntan? La respuesta está en las tareas de WP7, que nos permiten lanzar aplicaciones tales como el navegador o el reproductor de vídeo. Para ello añadimos primero un manejador de evento al SelectionChanged de la listbox:

Código :

<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Videos}"
         SelectionChanged="ListBox_SelectionChanged">

Y ahora en el manejador lanzamos la tarea de vídeo con los datos que tenemos del elemento seleccionado:

Código :

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.AddedItems.Count > 0)
    {
        ElementoEntradaVideo element=e.AddedItems[0] as ElementoEntradaVideo;
        if (element != null)
        {
            new MediaPlayerLauncher
            {
                Media=new Uri(element.Video),
                Controls=MediaPlaybackControls.All
            }.Show();
        }
    }
}

Así al pulsar sobre un elemento ya podremos ver el vídeo. Para el caso de los artículos y noticias vamos a lanzar el navegador con una dirección url:

Código :

private void ListBox_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
    if (e.AddedItems.Count > 0)
    {
        ElementoEntradaRss element=e.AddedItems[0] as ElementoEntradaRss;
        if (element != null)
        {
            new WebBrowserTask
            {
                URL=element.Link
            }.Show();
        }
    }
}

En unas pocas líneas hemos creado una aplicación completamente funcional.

Descarga el código de ejemplo

Conclusiones


En este primer tutorial hemos aprendido cómo empezar una aplicación para WP7 usando el control Panorama, nos hemos introducido en el patrón MVVM que suelen usar las aplicaciones de datos en Silverlight, hemos consumido datos de fuentes rss y hemos abierto vídeos y enlaces usando las tareas de Windows Phone. En el próximo capítulo vamos a empezar a refinar la aplicación: cambiaremos el aspecto visual de la aplicación y añadiremos alguna vista más aparte de la principal para mejorar la experiencia de usuario.

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate