Parte 5: Crear un lector de blogs (aplicaciones de la Tienda Windows con C#/VB y XAML)

Applies to Windows only

En este tema te presentamos el código esencial y las nociones básicas que necesitas para crear una aplicación de la Tienda Windows con C# o Visual Basic. Usaremos XAML para definir la interfaz de usuario, así como el lenguaje que escojas para escribir la lógica de la aplicación.

Importante  Este tutorial está diseñado para usarse con Microsoft Visual Studio 2012 y Windows 8. Algunas partes del tutorial no funcionarán correctamente con Microsoft Visual Studio 2013 y Windows 8.1.

Si prefieres usar otro lenguaje de programación, consulta:

Guía básica: ¿Qué relación tiene este tema con los demás? Consulta Guía básica para crear aplicaciones de Windows en tiempo de ejecución con C# o Visual Basic.

Antes de comenzar...

Objetivos

En este tutorial, daremos un paseo rápido por las características que se usan para crear aplicaciones de la Tienda Windows. Siguiendo el proceso de creación de una sencilla aplicación de lector de blogs, plantearemos los conceptos fundamentales para el desarrollo con XAML, como diseño, controles, plantillas y enlace de datos. Aprenderás a usar la navegación y las plantillas de página que hay integradas en Microsoft Visual Studio Express 2012 para Windows 8 para empezar a desarrollar nuestra aplicación rápidamente. Tras ello, aprenderás a usar estilos personalizados para modificar la apariencia de la aplicación y a adaptar la interfaz de usuario a varios diseños y vistas. Por último, analizaremos brevemente cómo integrar nuestra aplicación con Windows 8 y cómo publicarla en la Tienda Windows. Al terminar este tutorial, estarás listo para comenzar a crear tus propias aplicaciones de la Tienda Windows.

Hello World

Al crear una aplicación de la Tienda Windows con C# o Visual Basic, la interfaz de usuario se suele definir con XAML, y la lógica de la aplicación se escribe en un archivo de código subyacente asociado en el lenguaje que hayas seleccionado. El marco de interfaz de usuario de XAML para aplicaciones de la Tienda Windows mediante C# o Visual Basic se encuentra en los espacios de nombres Windows.UI.Xaml.* de Windows en tiempo de ejecución. Si has escrito aplicaciones con Windows Presentation Foundation (WPF), Microsoft Silverlight o Silverlight para Windows Phone, ya estás familiarizado con este modelo de programación y puedes usar esta experiencia para crear tu aplicación de la Tienda Windows con C# o Visual Basic.

Este ejemplo muestra el XAML que define la interfaz de usuario para una aplicación "Hello World!" sencilla y la página de código subyacente asociada. Ya en un ejemplo tan sencillo como el que nos ocupa hay varios conceptos importantes para el modelo de programación basado en XAML, como clases parciales, diseño, controles, propiedades y eventos.



<Page
    x:Class="WindowsBlogReader.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WindowsBlogReader"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <Button Content="Click Me" Click="HelloButton_Click" />
            <TextBlock x:Name="DisplayText" FontSize="48" />
        </StackPanel>
    </Grid>
</Page>



using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace WindowsBlogReader
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void HelloButton_Click(object sender, RoutedEventArgs e)
        {
            DisplayText.Text = "Hello, world";
        }
    }
}

Si bien una aplicación "Hello World!" es una buena forma de comenzar, no te llevará muy lejos en cuanto a rentabilidad, por lo que tomaremos otro camino para crear aplicaciones de la Tienda Windows. La aplicación de ejemplo que usas para comenzar es un sencillo lector de blogs para descargar y mostrar datos de una fuente Really Simple Syndication (RSS) 2.0 o Atom 1.0. Parece apropiado utilizar las fuentes del sitio The Windows Blog. Cuando termines, la aplicación tendrá el siguiente aspecto.

Ejemplo de navegación de tres páginas.

Crear aplicaciones de la Tienda Windows en Visual Studio

En esta sección aprenderás a:

  • crear una nueva aplicación de la Tienda Windows en Visual Studio Express 2012 para Windows 8.

Visual Studio es un eficaz entorno de desarrollo integrado (IDE) para desarrollar aplicaciones de Windows. Proporciona administración de los archivos de origen; compatibilidad integrada de creación, implementación y lanzamiento; XAML, Visual Basic, C#, C++, gráficos, edición de manifiestos y depuración, entre otras muchas cosas. Visual Studio tiene varias ediciones; usarás Visual Studio Express 2012 para Windows 8. Puedes descargarlo de forma gratuita junto con el kit de desarrollo de software (SDK) de Windows para Windows 8; de este modo, dispondrás de todo lo necesario para crear, empaquetar e implementar aplicaciones de la Tienda Windows.

Para comenzar a crear una aplicación, hay que crear un proyecto nuevo Tienda Windows con C# o Visual Basic. Visual Studio Express 2012 para Windows 8 incluye varias plantillas de proyectos Tienda Windows que ofrecen algunos diseños para ayudarte a comenzar con las aplicaciones. La plantilla de proyecto Aplicación vacía (XAML) proporciona los archivos mínimos que necesitas para todas las aplicaciones de la Tienda Windows.

Para obtener más información sobre Visual Studio Express 2012 for Windows 8, consulta Desarrollar aplicaciones de la Tienda Windows con Visual Studio 2012.

BR211380.wedge(es-es,WIN.10).gifPara crear un nuevo proyecto Tienda Windows

  1. Abre Visual Studio Express 2012 para Windows 8.
  2. Selecciona Archivo > Nuevo proyecto. Se abre el cuadro de diálogo Nuevo proyecto.
  3. En Plantillas en el panel izquierdo, expande Visual C# o Visual Basic.
  4. Selecciona el tipo de plantilla Tienda Windows.
  5. En el panel central, selecciona Aplicación vacía (XAML).
  6. Escribe un nombre para el proyecto. Llama a este proyecto "WindowsBlogReader".

    Así es como se crea un proyecto en Visual Studio Express 2012 para Windows 8.

    Cuadro de diálogo Nuevo proyecto de Visual Studio.

  7. Haz clic en Aceptar. Se crean los archivos del proyecto.

Cuando creas el proyecto, Visual Studio crea los archivos del proyecto y los muestra en el Explorador de soluciones. Veamos los archivos y las carpetas creados por la plantilla de aplicación vacía (XAML).

Nombre de archivoDescripción
Properties/AssemblyInfo (.vb or .cs)Contiene los metadatos de nombre y versión que se incrustan en el ensamblado generado.
Package.appxmanifestContiene metadatos que describen la aplicación, por ejemplo, nombre para mostrar, descripción, logotipos y capacidades.
Assets/*El logotipo predeterminado y las imágenes de la pantalla de presentación que puedes reemplazar por las tuyas propias.
Common/StandardStyles.xamlContiene las plantillas y estilos predeterminados de la aplicación.
App.xaml, App.xaml.cs/vbEstos archivos especifican lógica de nivel de la aplicación. La clase App es necesaria para que la interfaz de usuario se muestre.
MainPage.xamlLa página de inicio predeterminada que se usa para crear la interfaz de usuario.
MainPage.xaml.cs/vbEl archivo de código subyacente que contiene la lógica de la página de inicio predeterminada.

 

Para obtener más información sobre estos archivos y plantillas, consulta Plantillas para acelerar el desarrollo de la aplicación.

Incorporar datos a una aplicación

En esta sección aprenderás a:

  • crear una clase de datos personalizada
  • recuperar una fuente de datos Atom o RSS de forma asincrónica.

Antes de crear la interfaz de usuario de la aplicación, escribe el código para obtener los datos de fuente del blog para poder mostrar algo en la interfaz de usuario. En The Windows Blog se expone el texto completo de las entradas tanto en formato RSS como Atom. Los datos del blog que quieres mostrar en la aplicación de lector son el título, el autor, la fecha y el contenido de las últimas entradas del blog.

Para empezar, necesitas descargar los datos de cada una de las entradas de blog. Por suerte, Windows en tiempo de ejecución contiene un conjunto de clases que realiza automáticamente gran parte del trabajo de procesamiento de los datos de la fuente. Estas clases las encontramos en el espacio de nombres Windows.Web.Syndication. Estas clases se pueden usar directamente para mostrar los datos en la interfaz de usuario. Pero en nuestro lector de blogs, creas tus propias clases de datos. Esto te da más flexibilidad y permite tratar las fuentes RSS y Atom del mismo modo.

Usa tres clases para almacenar y recuperar los datos de fuente en la aplicación de lector de blogs. Colocas las tres clases en un archivo denominado FeedData.cs/vb. La clase FeedData contiene información sobre la fuente RSS o Atom. La clase FeedItem contiene información sobre las entradas de blog individuales que la fuente contiene. La clase FeedDataSource contiene una colección de fuentes y un método para recuperar las fuentes de la red.

BR211380.wedge(es-es,WIN.10).gifPara agregar una clase de datos al proyecto

  1. Selecciona Proyecto > Agregar clase. Se abre el cuadro de diálogo Nuevo elemento.
  2. Escribe "FeedData" como nombre del archivo de clase.
  3. Haz clic en Agregar. Se crea el nuevo archivo de clase.
  4. Copia este código en el archivo FeedData.cs/vb. Reemplaza todo el código existente en el archivo.
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Threading.Tasks;
    using Windows.Web.Syndication;
    
    namespace WindowsBlogReader
    {
        // FeedData
        // Holds info for a single blog feed, including a list of blog posts (FeedItem).
        public class FeedData
        {
            public string Title { get; set; }
            public string Description { get; set; }
            public DateTime PubDate { get; set; }
    
            private List<FeedItem> _Items = new List<FeedItem>();
            public List<FeedItem> Items
            {
                get
                {
                    return this._Items;
                }
            }
        }
    
        // FeedItem
        // Holds info for a single blog post.
        public class FeedItem
        {
            public string Title { get; set; }
            public string Author { get; set; }
            public string Content { get; set; }
            public DateTime PubDate { get; set; }
            public Uri Link { get; set; }
        }
    
        // FeedDataSource
        // Holds a collection of blog feeds (FeedData), and contains methods needed to
        // retreive the feeds.
        public class FeedDataSource
        {
            private ObservableCollection<FeedData> _Feeds = new ObservableCollection<FeedData>();
            public ObservableCollection<FeedData> Feeds
            {
                get
                {
                    return this._Feeds;
                }
            }
    
            public async Task GetFeedsAsync()
            {
                Task<FeedData> feed1 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx");
                Task<FeedData> feed2 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx");
                Task<FeedData> feed3 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/extremewindows/atom.aspx");
                Task<FeedData> feed4 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/business/atom.aspx");
                Task<FeedData> feed5 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx");
                Task<FeedData> feed6 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/windowssecurity/atom.aspx");
                Task<FeedData> feed7 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/springboard/atom.aspx");
                Task<FeedData> feed8 =
                    GetFeedAsync("http://windowsteamblog.com/windows/b/windowshomeserver/atom.aspx");
                // There is no Atom feed for this blog, so use the RSS feed.
                Task<FeedData> feed9 =
                    GetFeedAsync("http://windowsteamblog.com/windows_live/b/windowslive/rss.aspx");
                Task<FeedData> feed10 =
                    GetFeedAsync("http://windowsteamblog.com/windows_live/b/developer/atom.aspx");
                Task<FeedData> feed11 =
                    GetFeedAsync("http://windowsteamblog.com/ie/b/ie/atom.aspx");
                Task<FeedData> feed12 =
                    GetFeedAsync("http://windowsteamblog.com/windows_phone/b/wpdev/atom.aspx");
                Task<FeedData> feed13 =
                    GetFeedAsync("http://windowsteamblog.com/windows_phone/b/wmdev/atom.aspx");
                Task<FeedData> feed14 =
                    GetFeedAsync("http://windowsteamblog.com/windows_phone/b/windowsphone/atom.aspx");
    
                this.Feeds.Add(await feed1);
                this.Feeds.Add(await feed2);
                this.Feeds.Add(await feed3);
                this.Feeds.Add(await feed4);
                this.Feeds.Add(await feed5);
                this.Feeds.Add(await feed6);
                this.Feeds.Add(await feed7);
                this.Feeds.Add(await feed8);
                this.Feeds.Add(await feed9);
                this.Feeds.Add(await feed10);
                this.Feeds.Add(await feed11);
                this.Feeds.Add(await feed12);
                this.Feeds.Add(await feed13);
                this.Feeds.Add(await feed14);
            }
    
            private async Task<FeedData> GetFeedAsync(string feedUriString)
            {
                Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
                Uri feedUri = new Uri(feedUriString);
    
                try
                {
                    SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);
    
                    // This code is executed after RetrieveFeedAsync returns the SyndicationFeed.
                    // Process the feed and copy the data you want into the FeedData and FeedItem classes.
                    FeedData feedData = new FeedData();
    
                    if (feed.Title != null && feed.Title.Text != null)
                    {
                        feedData.Title = feed.Title.Text;
                    }
                    if (feed.Subtitle != null && feed.Subtitle.Text != null)
                    {
                        feedData.Description = feed.Subtitle.Text;
                    }
                    if (feed.Items != null && feed.Items.Count > 0)
                    {
                        // Use the date of the latest post as the last updated date.
                        feedData.PubDate = feed.Items[0].PublishedDate.DateTime;
    
                        foreach (SyndicationItem item in feed.Items)
                        {
                            FeedItem feedItem = new FeedItem();
                            if (item.Title != null && item.Title.Text != null)
                            {
                                feedItem.Title = item.Title.Text;
                            }
                            if (item.PublishedDate != null)
                            {
                                feedItem.PubDate = item.PublishedDate.DateTime;
                            }
                            if (item.Authors != null && item.Authors.Count > 0)
                            {
                                feedItem.Author = item.Authors[0].Name.ToString();
                            }
                            // Handle the differences between RSS and Atom feeds.
                            if (feed.SourceFormat == SyndicationFormat.Atom10)
                            {
                                if (item.Content != null && item.Content.Text != null)
                                {
                                    feedItem.Content = item.Content.Text;
                                }
                                if (item.Id != null)
                                {
                                    feedItem.Link = new Uri("http://windowsteamblog.com" + item.Id);
                                }
                            }
                            else if (feed.SourceFormat == SyndicationFormat.Rss20)
                            {
                                if (item.Summary != null && item.Summary.Text != null)
                                {
                                    feedItem.Content = item.Summary.Text;
                                }
                                if (item.Links != null && item.Links.Count > 0)
                                {
                                    feedItem.Link = item.Links[0].Uri;
                                }
                            }
                            feedData.Items.Add(feedItem);
                        }    
                    }
                    return feedData;
                }
                catch (Exception)
                {
                    return null;
                }
            }
    
            // Returns the feed that has the specified title.
            public static FeedData GetFeed(string title)
            {
                // Simple linear search is acceptable for small data sets
                var _feedDataSource = App.Current.Resources["feedDataSource"] as FeedDataSource;
    
                var matches = _feedDataSource.Feeds.Where((feed) => feed.Title.Equals(title));
                if (matches.Count() == 1) return matches.First();
                return null;
            }
    
            // Returns the post that has the specified title.
            public static FeedItem GetItem(string uniqueId)
            {
                // Simple linear search is acceptable for small data sets
                var _feedDataSource = App.Current.Resources["feedDataSource"] as FeedDataSource;
                var _feeds = _feedDataSource.Feeds;
    
                var matches = _feedDataSource.Feeds.SelectMany(group => group.Items).Where((item) => item.Title.Equals(uniqueId));
                if (matches.Count() == 1) return matches.First();
                return null;
            }
        }
    }
    
    
  5. Haz clic en Compilar > Compilar solución para asegurarte de que la solución se genera sin errores.

Recuperar los datos de fuente

Veamos más en detalle cómo se descargan las fuentes de los blogs. Como la clase Windows.Web.Syndication.SyndicationClient recupera una fuente RSS o Atom completamente analizada, puedes usar los datos sin preocuparte de analizar el código XML. Para descargar una fuente mediante la clase SyndicationClient, tienes que usar el método RetrieveFeedAsync asincrónico. El modelo de programación asincrónica es frecuente en Windows en tiempo de ejecución para ayudar a que las aplicaciones respondan. Afortunadamente, ya se ha eliminado gran parte de la complejidad que se puede esperar cuando se utilizan métodos asincrónicos.

Usar await en C# y Visual Basic

Si usas la palabra clave await en C# y Visual Basic, el código para recuperar la fuente de forma asincrónica es similar al código que usarías para recuperar la fuente de forma sincrónica. Echemos un vistazo.

En el método GetFeedsAsync, llamas a GetFeedAsync por cada fuente de blog que quieras recuperar. Siempre que sea posible, pasa la dirección URL para la fuente Atom, porque incluye datos de autor que deseas mostrar. Si no hay ninguna fuente Atom, usa la fuente RSS. Cada fuente de blog devuelta se agrega a la colección FeedDataSource.Feeds.

Si usas métodos sincrónicos, el código podría tener el siguiente aspecto. En este código, el método GetFeed devuelve un objeto FeedData. Cuando se devuelve FeedData, se agrega a la colección Feeds.



public void GetFeeds()
{
    FeedData feed1 = 
        GetFeed("http://windowsteamblog.com/windows/b/developers/atom.aspx");
    ...
    this.Feeds.Add(feed1);
    ...
}

Ahora veamos cómo puedes hacer lo mismo usando métodos "asincrónicos" y cómo puede ayudarte la palabra clave await. Lo primero que vemos es que agregas la palabra clave async a la firma del método. La palabra clave await solo se puede usar en un método que se haya definido como async. Especificas el tipo de valor devuelto de GetFeedsAsync como Task.



public async Task GetFeedsAsync()
{
    Task<FeedData> feed1 = 
        GetFeedAsync("http://windowsteamblog.com/windows/b/developers/atom.aspx");
    ...
    this.Feeds.Add(await feed1);
    ...
}

En tu código asincrónico, el método GetFeedAsync devuelve Task<FeedData>, o Task(Of FeedData) en VB, que representa el FeedData que finalmente será el valor devuelto del método.

En este punto del código:


this.Feeds.Add(await feed1);

se realiza la llamada a GetFeedAsync y se devuelve Task<FeedData>. A continuación, se ejecuta la siguiente línea de código (para obtener feed2), pero feed1 no se agrega a la colección Feeds hasta que el objeto FeedData se pasa realmente al Task<FeedData> que lo espera. En breve volveremos a este punto. Ahora vamos a ver qué ocurre en el método GetFeedAsync.

Especificas el tipo de valor devuelto de GetFeedAsync como Task<FeedData>. De esta forma, se indica al compilador que genere una Task que represente al objetoFeedData que el método recupera.


private async Task<FeedData> GetFeedAsync(string feedUriString)
{
...
}

En el método, creas una instancia de SyndicationClient y llamas a su método RetrieveFeedAsync para obtener la fuente SyndicationFeed que contiene la información de RSS o Atom que quieres.


Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
Uri feedUri = new Uri(feedUriString);
...
    SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

Dado que RetrieveFeedAsync es un método asincrónico, usas de nuevo la palabra clave await. La palabra clave await le dice al compilador que haga el trabajo automáticamente en segundo plano. Después de esta llamada, el compilador programa el resto del método como una devolución de llamada que se ejecutará cuando la llamada vuelva. A continuación, devuelve el control inmediatamente al subproceso que llama (que suele ser el subproceso de la interfaz de usuario) para que la aplicación siga respondiendo. Llegado este punto, la Task<FeedData> que representa el resultado final de este método (un objeto FeedData) se devuelve al llamador.

Cuando RetrieveFeedAsync devuelve SyndicationFeed con los datos que quieres, se ejecuta el resto del código de tu método. Y, lo que es importante, se ejecuta en el mismo contexto de subproceso desde el que realizaste la llamada original (el subproceso de la interfaz de usuario), para que no tengas que preocuparte de usar un distribuidor si quieres actualizar la interfaz de usuario en este código. Una vez que hayas recuperado SyndicationFeed, copias las partes que necesitas en tus clases de datos FeedData y FeedItem.



// This code is executed after RetrieveFeedAsync returns the SyndicationFeed.
// Process the feed and copy the data you want into the FeedData and FeedItem classes.
FeedData feedData = new FeedData();

if (feed.Title != null && feed.Title.Text != null)
{
    feedData.Title = feed.Title.Text;
}
if (feed.Subtitle != null && feed.Subtitle.Text != null)
{
    feedData.Description = feed.Subtitle.Text;
}
if (feed.Items != null && feed.Items.Count > 0)
{
    // Use the date of the latest post as the last updated date.
    feedData.PubDate = feed.Items[0].PublishedDate.DateTime;

    foreach (SyndicationItem item in feed.Items)
    {
        FeedItem feedItem = new FeedItem();
        if (item.Title != null && item.Title.Text != null)
        {
            feedItem.Title = item.Title.Text;
        }
        if (item.PublishedDate != null)
        {
            feedItem.PubDate = item.PublishedDate.DateTime;
        }
        if (item.Authors != null && item.Authors.Count > 0)
        {
            feedItem.Author = item.Authors[0].Name.ToString();
        }
        // Handle the differences between RSS and Atom feeds.
        if (feed.SourceFormat == SyndicationFormat.Atom10)
        {
            if (item.Content != null && item.Content.Text != null)
            {
                feedItem.Content = item.Content.Text;
            }
            if (item.Id != null)
            {
                feedItem.Link = new Uri("http://windowsteamblog.com" + item.Id);
            }
        }
        else if (feed.SourceFormat == SyndicationFormat.Rss20)
        {
            if (item.Summary != null && item.Summary.Text != null)
            {
                feedItem.Content = item.Summary.Text;
            }
            if (item.Links != null && item.Links.Count > 0)
            {
                feedItem.Link = item.Links[0].Uri;
            }
        }
        feedData.Items.Add(feedItem);
    }    
}
return feedData;

Cuando el código llega a la instrucción return, realmente no estas devolviendo en el sentido en el que devuelve un método sincrónico. Recuerda que el método se devolvió al llamador inmediatamente después de la instrucción "await". Devolvió una Task<FeedData> para representar el resultado final del método. Aquí, finalmente, obtienes el resultado. La línea return feedData; proporciona el objeto FeedData, que es el resultado del método para Task<FeedData>, que está a la espera.

Se esperó a Task en esta línea en el método GetFeedsAsync.


this.Feeds.Add(await feed1);

Cuando Task obtiene el resultado de FeedData que está esperando, el código se ejecuta y FeedData se agrega a la colección FeedDataSource.Feeds.

Usar los datos en la aplicación

Para usar los datos en la aplicación, creas una instancia del origen de datos como un recurso en App.xaml. Denominas a la instancia feedDataSource.

BR211380.wedge(es-es,WIN.10).gifPara agregar un recurso a una aplicación

  1. En el Explorador de soluciones, haz doble clic en App.xaml. El archivo se abre en el editor de XAML.
  2. Agrega la declaración de recurso, <local:FeedDataSource x:Key="feedDataSource"/>, a la raíz ResourceDictionary después de la colección MergedDictionaries.

Este es el código XAML completo de la sección Application.Resources después de agregar el nuevo recurso.


    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!-- 
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            
            <local:FeedDataSource x:Key="feedDataSource"/>
        </ResourceDictionary>
    </Application.Resources>

Para recuperar las fuentes, agregas código a la invalidación del método OnLaunched en el archivo App.xaml.cs/vb. Este método se ejecuta cada vez que un usuario inicia la aplicación.

Primero, agregas la palabra clave async a la declaración del método porque usas la palabra clave await en el método. Dado que la aplicación requiere de una conexión activa a Internet para descargar fuentes, usas la claseNetworkInformation para comprobar si existe una conexión. Si la aplicación está conectada, descargas las fuentes. De lo contrario, notificas al usuario. Luego agregas código para obtener la instancia de FeedDataSource de la aplicación y compruebas si ya contiene fuentes. Si no las contiene, llamas al método FeedDataSource.GetFeedsAsync para recuperar las fuentes.

BR211380.wedge(es-es,WIN.10).gifPara recuperar las fuentes

  1. En el Explorador de soluciones, haz doble clic en App.xaml.cs/vb. El archivo se abre en el editor de código.
  2. Agrega la palabra clave async a la firma del método OnLaunched.
    
    protected async override void OnLaunched(LaunchActivatedEventArgs args)
    
    
  3. Agrega este código al método OnLaunched, inmediatamente después de la creación de instancias del nuevo Frame, rootFrame = New Frame().
    
                    // Add this code after "rootFrame = new Frame();"
                    var connectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
                    if (connectionProfile != null)
                    {
                        FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
                        if (feedDataSource != null)
                        {
                            if (feedDataSource.Feeds.Count == 0)
                            {
                                await feedDataSource.GetFeedsAsync();
                            }
                        }
                    }
                    else
                    {
                        var messageDialog = new Windows.UI.Popups.MessageDialog("An internet connection is needed to download feeds. Please check your connection and restart the app.");
                        var result = messageDialog.ShowAsync();
                    }
    
    

Este es el código completo del método OnLaunched después de agregar el código.


        protected async override void OnLaunched(LaunchActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                // Add this code after "rootFrame = new Frame();"
                var connectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
                if (connectionProfile != null)
                {
                    FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
                    if (feedDataSource != null)
                    {
                        if (feedDataSource.Feeds.Count == 0)
                        {
                            await feedDataSource.GetFeedsAsync();
                        }
                    }
                }
                else
                {
                    var messageDialog = new Windows.UI.Popups.MessageDialog("An internet connection is needed to download feeds. Please check your connection and restart the app.");
                    var result = messageDialog.ShowAsync();
                }

                if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                if (!rootFrame.Navigate(typeof(ItemsPage), args.Arguments))
                {
                    throw new Exception("Failed to create initial page");
                }
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

Puedes compilar y ejecutar la aplicación en modo de depuración para asegurarte de que las fuentes se crean y recuperan sin errores. Si no hay errores, la aplicación se ejecuta, pero solo muestra una pantalla negra. Si hay errores, Visual Studio mostrará información sobre ellos. Para obtener más información sobre la ejecución de aplicaciones en Visual Studio, consulta el tema sobre la ejecución de aplicaciones de la Tienda Windows en Visual Studio.

BR211380.wedge(es-es,WIN.10).gifPara ejecutar la aplicación en modo de depuración

  1. Para ejecutar la aplicación, realiza una de las siguientes acciones:
    • Haz clic en Depurar > Iniciar depuración.
    • Presiona F5.
  2. Para detener la depuración:
    1. Presiona Alt+Tab para regresar a Visual Studio.
    2. Realiza una de estas acciones en Visual Studio.
      • Haz clic en Depurar > Detener depuración.
      • Presiona Mayús+F5.

Ahora creas la interfaz de usuario para mostrar los datos.

Incorporación de páginas y navegación

Para mostrar los blogs de The Windows Blog, debes agregar páginas a la aplicación y controlar la navegación entre estas páginas. Primero, quieres que una página tenga una lista con todos los blogs de The Windows Blog. Cuando un lector se decide por un blog de esta página, navegas a una página nueva y cargas la lista de entradas de dicho blog. También agregas una página de detalles para que un usuario pueda leer entradas de blog individuales sin que la vista de lista ocupe espacio.

Plantillas de página

Afortunadamente, no es necesario que crees cada página desde una plantilla en blanco. Visual Studio Express 2012 para Windows 8 incorpora una colección de plantillas de página muy prácticas para diversas situaciones. Estas son las plantillas de página disponibles.

Tipo de páginaDescripción
Grupo Detail PageMuestra detalles para un solo grupo y vistas previas para cada elemento del grupo.
Grouped Items PageMuestra colecciones agrupadas.
Item Detail PageMuestra un elemento en detalle y permite navegar hacia elementos adyacentes.
Items PageMuestra una colección de elementos.
Split PageMuestra una lista de elementos y detalles para el elemento seleccionado.
Basic PageUna página vacía que puede adaptarse a distintas orientaciones y vistas, y que tiene un título y un botón Atrás.
Blank PagePágina vacía de una aplicación de la Tienda Windows

 

Usas la plantilla Página de elementos para mostrar la lista de blogs del sitio de The Windows Blog. Usas la plantilla Página dividida para mostrar las entradas de cada blog y el texto de la entrada seleccionada. Usas la plantilla Página básica para la página de detalles.

BR211380.wedge(es-es,WIN.10).gifPara agregar páginas a la aplicación

  1. Selecciona Proyecto > Agregar nuevo elemento. Se abre el cuadro de diálogo Agregar nuevo elemento.

    Este es el cuadro de diálogo Agregar nuevo elemento.

    Cuadro de diálogo Agregar nuevo elemento de Visual Studio.
  2. En Visual C# o Visual Basic en el panel izquierdo, elige el tipo de plantilla Tienda Windows.
  3. En el panel central, selecciona el tipo de página para agregar al proyecto. Selecciona la plantilla Items Page.
  4. Escribe un nombre para la página. Escribe "ItemsPage.xaml".
  5. Haz clic en Agregar.

    La primera vez que agregas una nueva página a la plantilla Blank App (distinta de una página en blanco), Visual Studio muestra un cuadro de diálogo con un mensaje que indica que debes agregar archivos que faltan en tu proyecto. Haz clic en para agregar esos archivos. Se agregan archivos para varias clases de utilidad al proyecto en la carpeta Common.

    El código XAML y los archivos de código subyacente de la página se agregan al proyecto.

  6. Haz clic en Compilar > Compilar solución para compilar la aplicación. La nueva página mostrará un error en el diseñador hasta que compiles las clases auxiliares de las que depende.
  7. Repite los pasos 1 a 5 para agregar una página dividida.
    • En el paso 3, selecciona la plantilla Split Page.
    • En el paso 4, asígnale a la página el nombre "SplitPage.xaml".
  8. Repite los pasos 1 a 5 para agregar una página básica.
    • En el paso 3, selecciona la plantilla Basic Page.
    • En el paso 4, asígnale a la página el nombre "DetailPage.xaml".

Cuando agregas las plantillas de página al proyecto y observas el XAML y el código subyacente, es evidente que estas plantillas de página te ahorran mucho trabajo. De hecho, es fácil perderse, así que vamos a analizar las plantillas de página más en profundidad para ver qué contienen. Todas las plantillas de página XAML para las aplicaciones de la Tienda Windows tienen el mismo formato.

El código XAML de este tipo de plantillas tiene tres secciones principales:

RecursosLos estilos y las plantillas de datos de la página se definen en la sección Resources. Encontrarás más información al respecto en la sección Creación de un aspecto coherente con estilos.
Contenido de la aplicaciónEl contenido y los controles que conforman la interfaz de usuario de una aplicación se definen en el panel de diseño raíz.
Visual State ManagerLas animaciones y transiciones que permiten adaptar la aplicación a los distintos diseños y orientaciones se definen en la sección VisualStateManager. Encontrarás más información al respecto en la sección Adaptación a distintos diseños.

 

Todas las páginas de plantilla que usas se derivan de la clase LayoutAwarePage y, de forma predetermina, tienen mucha más funcionalidad que la plantilla Página en blanco que se usa para MainPage.xaml en una aplicación vacía. LayoutAwarePage es una implementación de Page que reporta una funcionalidad importante para el desarrollo de aplicaciones de la Tienda Windows:

  • La asignación del estado de visualización de aplicación al estado visual hace posible que la página se adapte a distintas resoluciones, orientaciones y vistas.
  • Los controladores de eventos GoBack y GoHome admiten la navegación básica.
  • Un modelo de vista predeterminada constituye un origen de datos enlazable sencillo.
  • Los métodos SaveState y LoadState funcionan con la clase SuspensionManager para administrar el estado de sesión de la aplicación.

Las plantillas de página también usan los estilos y plantillas de StandardStyles.xaml, que aplican las pautas de diseño de las aplicaciones de la Tienda Windows. Usarás algunos de estos estilos como punto de partida y modificarás copias de estos con el propósito de personalizar la apariencia de la aplicación.

Navegación entre páginas

El marco de la interfaz de usuario de XAML proporciona un modelo de navegación integrado que usa controles Frame y Page y funciona en gran medida como la navegación en un explorador web. El control Frame hospeda controles Page y tiene un historial de navegación que se puede utilizar para ir hacia atrás y hacia adelante por las páginas que ya visitaste. Puedes pasar datos entre las páginas mientras navegas.

Navegación a ItemsPage

En las plantillas de proyecto de Visual Studio, se establece un Frame llamado rootFrame como contenido de la ventana de la aplicación. Este Frame hospeda todos los elementos Page de la aplicación. Veamos el código relevante en App.xaml.cs/vb.



        protected async override void OnLaunched(LaunchActivatedEventArgs args)
        {
            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

               ...

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
                {
                    throw new Exception("Failed to create initial page");
                }
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

Este código obtiene un Frame existente (si lo hay); de lo contrario, crea uno nuevo y lo establece como el contenido de la ventana. A continuación, navega a MainPage. Como quieres que la primera página de la aplicación sea ItemsPage, cambias la llamada al método Navigate y la pasas en ItemsPage como el elemento Page al que hay que navegar.

BR211380.wedge(es-es,WIN.10).gifPara navegar a ItemsPage

  1. En el Explorador de soluciones, haz doble clic en App.xaml.cs/vb. El archivo se abre en el editor de código.
  2. En el método OnLaunched, actualiza la llamada a rootFrame.Navigate y pasa ItemsPage como el primer parámetro, como se muestra aquí.
    
    
                if (!rootFrame.Navigate(typeof(ItemsPage), args.Arguments))
                {
                    throw new Exception("Failed to create initial page");
                }
    
    
    
  3. Presiona F5 para compilar y ejecutar la aplicación. Ahora se carga ItemsPage en lugar de la MainPage predeterminada.

    Nota  El archivo MainPage.xaml predeterminado ya no se necesita en este proyecto y puedes eliminarlo con seguridad.

En la página de elementos, todavía no ves ningún contenido porque no conectaste ningún dato a la interfaz de usuario. Lo harás ahora.

Carga de ItemsPage

Cuando se carga ItemsPage, debes obtener la instancia del origen de datos de la aplicación y enlazarla con la interfaz de usuario. En las páginas que se derivan de LayoutAwarePage, puedes enlazar tus datos al DefaultViewModel proporcionado por LayoutAwarePage. Debes hacerlo en la invalidación del método LoadState.

BR211380.wedge(es-es,WIN.10).gifPara cargar datos en la página de elementos

  1. Haz doble clic en ItemPage.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  2. Agrega este código al método LoadState.
    
                FeedDataSource feedDataSource = (FeedDataSource)App.Current.Resources["feedDataSource"];
    
                if (feedDataSource != null)
                {
                    this.DefaultViewModel["Items"] = feedDataSource.Feeds;
                }
    
    
  3. Presiona F5 para compilar y ejecutar la aplicación.

Se ha cargado la ItemsPage y muestra una cuadrícula de todos los blogs. Tendrá un aspecto similar a este, pero es posible que los elementos aparezcan organizados de otra forma en función de la resolución de tu pantalla.

Página de elementos

Navegación a SplitPage

Cuando el usuario elige un blog de la colección, navegas de la página de elementos a la página de división. Para realizar esta navegación, quieres que los elementos GridView respondan a un clic como un botón en lugar de ser seleccionados. Para que se pueda hacer clic en los elementos GridView, defines las propiedades SelectionMode y IsItemClickEnabled como se indica aquí. A continuación, agregas un controlador para el evento ItemClick de GridView.

BR211380.wedge(es-es,WIN.10).gifPara navegar a SplitPage

  1. Haz doble clic en ItemsPage.xaml en el Explorador de soluciones para abrirlo.
  2. Selecciona el control GridView denominado itemGridView.
  3. En el panel Propiedades, expande la sección Común y luego haz clic en la flecha abajo situada en la parte inferior de la sección para expandir las propiedades avanzadas.
  4. Activa la casilla de la capacidad IsItemClickEnabled. De este modo se establece la propiedad en true.
  5. Agrega un controlador para el evento ItemClick.
    1. En el panel Propiedades, haz clic en el botón Eventos (Botón de eventos).
    2. Busca el evento ItemClick en la lista de eventos. En el cuadro de texto del evento, escribe "ItemView_ItemClick" como nombre del método que controla el evento ItemClick.
    3. Presiona Entrar. El método de controlador de eventos se crea y se abre en un editor de código, de forma que puedes agregar código que se ejecutará cuando se produzca el evento.
    4. Agrega este código al controlador de eventos ItemView_ItemClick en la página de código subyacente.

      Desde aquí, navegamos a la página de división y pasamos el nombre de la fuente seleccionada.

      
                  // Navigate to the split page, configuring the new page
                  // by passing the title of the clicked item as a navigation parameter
      
                  if (e.ClickedItem != null)
                  {
                      string title = ((FeedData)e.ClickedItem).Title;
                      this.Frame.Navigate(typeof(SplitPage), title);
                  }
      
      
  6. En ItemsPage.xaml, selecciona el control ListView denominado itemListView.
  7. En la Ventana de propiedades, haz clic en el botón de propiedades (Botón de eventos).
  8. Repite el procedimiento del paso 4 al paso 5.3 para el control itemListView.

La lista itemListView se muestra en lugar de la cuadrícula cuando la aplicación está acoplada. Encontrarás más información al respecto en la sección Adaptación a distintos diseños. Por ahora solo necesitas efectuar en ListView los mismos cambios que hiciste en GridView para que, de este modo, tengan el mismo comportamiento.

Para navegar entre páginas, se usan los métodos Navigate, GoForward y GoBack del control Frame. Para desplazarse hacia atrás, las plantillas de página de Visual Studio incluyen un botón Atrás. El controlador para el evento Click de BackButton llama al método Frame.GoBack.

El método Navigate(TypeName, Object) permite navegar y pasar objetos de datos a la página nueva. Usas este método para pasar datos entre tus páginas. El primer parámetro, typeof(SplitPage), es el Type de la página a la que estás navegando. El segundo parámetro es el objeto de datos que pasas a la página a la que estás navegando. En este caso, pasas el título del elemento en el que se ha hecho clic.

Podrías pasar tus objetos de datos personalizados como parámetros de navegación, pero no serán persistentes e incluso producirán una excepción cuando guardes el estado de sesión de la aplicación mediante la clase SuspensionManager. Para guardar el estado de navegación de la aplicación mediante SuspensionManager, solo debes pasar como parámetros de navegación tipos básicos y serializables. Por eso pasas el título del elemento y haces que un método de la clase FeedDataSource obtenga el elemento del título.

Antes de pasar a la página dividida, debes hacer un cambio más en la página de elementos. El título de página predeterminado es "Mi aplicación". Lo cambias por "The Windows Blog".

BR211380.wedge(es-es,WIN.10).gifPara cambiar el título de página

  1. Haz doble clic en ItemsPage.xaml en el Explorador de soluciones para abrirlo.
  2. Selecciona el TextBlock denominado pageTitle.
  3. En la Ventana de propiedades, haz clic en el botón de propiedades (Botón de eventos).
  4. En Común en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad Text. Se abre el menú de propiedad.

    Nota  El marcador de propiedad es el símbolo de cuadro pequeño situado a la derecha de cada valor de propiedad. El marcador de propiedad Text de color verde indica que se ha establecido en un recurso.

  5. En el menú de propiedad, selecciona Editar recurso.... Se abre el cuadro de diálogo Editar recurso.
  6. En el cuadro de diálogo Editar recurso, cambia el valor "Mi aplicación" a "The Windows Blog".
  7. Haz clic en Aceptar.

En ItemsPage.xaml, el título de la página está enlazado a un recurso estático con la clave AppName. El texto de este recurso se actualiza a "The Windows Blog" y ahora el código XAML tiene este aspecto.


<x:String x:Key="AppName">Windows Team Blogs</x:String>

Presiona F5 para compilar y ejecutar la aplicación. Ahora al hacer clic en un elemento, se carga la página dividida. Pero la página de división aún está vacía porque aún no la has conectado a los datos.

Carga de SplitPage

En la página de código subyacente SplitPage.xaml.cs/vb, tienes que hacer algo con el objeto que se acaba de pasar de la página de elementos. Para ello, invalidas el método LoadState. Este método ya se ha agregado en el código de la plantilla de la página, por lo que solo es necesario que lo modifiques para que enlace los datos. navigationParameter tiene el objeto de datos que se pasó de la página de elementos. Vuelves a convertir esto en un objeto string y lo pasas como parámetro al método FeedDataSource.GetFeed. Agregas los datos de fuente devueltos a DefaultViewModel con la clave Feed y agregas la propiedad FeedData.Items a DefaultViewModel con la clave Items.

BR211380.wedge(es-es,WIN.10).gifPara cargar datos en la página dividida

  1. Haz doble clic en SplitPage.xaml.cs/vb en el Explorador de soluciones para abrirlo en el editor de código.
  2. Agrega este código a la parte superior del método LoadState, después de los comentarios "TODO".

    Sugerencia  Expande la sección "Administración del estado de página" para ver el método LoadState.

    
    
                // TODO: Assign a bindable group to this.DefaultViewModel["Group"]
                // TODO: Assign a collection of bindable items to this.DefaultViewModel["Items"]
                string feedTitle = (string)navigationParameter;
                FeedData feedData = FeedDataSource.GetFeed(feedTitle);
                if (feedData != null)
                {
                    this.DefaultViewModel["Feed"] = feedData;
                    this.DefaultViewModel["Items"] = feedData.Items;
                }
    
    

Este es el método LoadState actualizado.



        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            // TODO: Assign a bindable group to this.DefaultViewModel["Group"]
            // TODO: Assign a collection of bindable items to this.DefaultViewModel["Items"]
            string feedTitle = (string)navigationParameter;
            FeedData feedData = FeedDataSource.GetFeed(feedTitle);
            if (feedData != null)
            {
                this.DefaultViewModel["Feed"] = feedData;
                this.DefaultViewModel["Items"] = feedData.Items;
            }

            if (pageState == null)
            {
                // When this is a new page, select the first item automatically unless logical page
                // navigation is being used (see the logical page navigation #region below.)
                if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
                {
                    this.itemsViewSource.View.MoveCurrentToFirst();
                }
            }
            else
            {
                // Restore the previously saved state associated with this page
                if (pageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
                {
                    // TODO: Invoke this.itemsViewSource.View.MoveCurrentTo() with the selected
                    //       item as specified by the value of pageState["SelectedItem"]
                }
            }
        }

Presiona F5 para compilar y ejecutar la aplicación. Ahora, cuando navegues a la página de división, se muestran los datos y puedes seleccionar de la lista de entradas de blog. Pero el título de la página sigue vacío. Arreglarás esto ahora.

En la plantilla de página de Visual Studio, los comentarios "TODO" reflejan dónde agregas el objeto de datos en DefaultViewModel con la clave Group.



            // TODO: Assign a bindable group to this.DefaultViewModel["Group"]
            ...
                this.DefaultViewModel["Feed"] = feedData;


Puedes pensar en una fuente del blog como en un grupo de entradas del blog, pero el código será más fácil de leer si usas la clave Feed en lugar de Group. Como has usado la clave Feed en su lugar, tienes que cambiar el enlace en el título de página para enlazar con la propiedad Feed y no con Group. También extiendes el título para que ocupe dos columnas y no quede cortado.

BR211380.wedge(es-es,WIN.10).gifPara actualizar el título de página

  1. Haz doble clic en SplitPage.xaml en el Explorador de soluciones para abrirlo.
  2. Selecciona el Grid denominado titlePanel.
  3. En Diseño en el panel Propiedades, establece la propiedad ColumnSpan en "2" y presiona Entrar.

    Nota  En el ancho predeterminado del panel Propiedades, la propiedad ColumnSpan se muestra como Columna....

    El XAML se actualiza como se muestra aquí.

    
    <!-- Back button and page title -->
    <Grid x:Name="titlePanel" Grid.ColumnSpan="2">
    
    
  4. Selecciona el TextBlock denominado pageTitle.
  5. En Común en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad Text. Se abre el menú de propiedad.

    Nota  El marcador de propiedad Text de color naranja indica que se ha establecido en un enlace.

  6. En el menú de propiedad, selecciona Crear enlace de datos.... Se abrirá el cuadro de diálogo Crear enlace de datos.
  7. En el cuadro de diálogo Crear enlace de datos, cambia el valor del cuadro de texto Ruta a "Feed.Title" y haz clic en Aceptar.

    El XAML para el TextBlock se actualiza de esta manera.

    
    <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{Binding Feed.Title}" 
               Style="{StaticResource PageHeaderTextStyle}"/>
    
    
  8. Presiona F5 para compilar y ejecutar la aplicación. Ahora, cuando navegas a la página dividida, se muestra el título de la página.

Página dividida con estilos predeterminados

Agregar WebView

De manera predeterminada, la plantilla de página dividida muestra los detalles del elemento seleccionado en un TextBlock. Sin embargo, la cadena que tiene el contenido de la entrada no es texto sin formato, sino una cadena de HTML. Si muestras la cadena en un TextBlock, ves numerosas etiquetas HTML y no quieres que eso ocurra. En lugar de ello, usas un control WebView para mostrar el HTML. También cambias el diseño que se usa para mostrar el título y el contenido de la entrada de blog seleccionada.

BR211380.wedge(es-es,WIN.10).gifPara agregar la vista web

  1. En SplitPage.xaml, elimina el ScrollViewer denominado itemDetail y todo su contenido.
  2. En el editor XAML, agrega este XAML en lugar del ScrollViewer itemDetail que has eliminado.
    
            <!-- Details for selected item -->
            <ScrollViewer
                x:Name="itemDetail"
                AutomationProperties.AutomationId="ItemDetailScrollViewer"
                Grid.Column="1"
                Grid.Row="1"
                Padding="70,0,120,0"
                DataContext="{Binding SelectedItem, ElementName=itemListView}"
                Style="{StaticResource VerticalScrollViewerStyle}">
            
                <Grid x:Name="itemDetailGrid">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
            
                    <TextBlock x:Name="itemTitle" Text="{Binding Title}" 
                               Style="{StaticResource SubheaderTextStyle}"/>
                    <Border x:Name="contentViewBorder" BorderBrush="Gray" BorderThickness="2" 
                            Grid.Row="1" Margin="0,15,0,20">
                        <Grid>
                            <WebView x:Name="contentView" />
                            <Rectangle x:Name="contentViewRect" />
                        </Grid>    
                    </Border>
                </Grid>
            </ScrollViewer>
    
    

El control WebView nos da una forma de hospedar datos HTML en la aplicación. Pero, si miras su propiedad Source, ves que se necesita un Uri de la página web para mostrarse. Los datos HTML son solo una cadena de HTML. No tiene un Uri que puedas enlazar a la propiedad Source. Por suerte, existe un método NavigateToString al cual puedes pasar tu cadena HTML.

Cuando uses un control WebView para ver contenido que podría no estar disponible, controla los posibles errores que se produzcan.

Aquí controlas el evento NavigationFailed para mostrar el mensaje de error en el control WebView si la navegación da error.

BR211380.wedge(es-es,WIN.10).gifPara controlar errores de navegación

  1. Selecciona la WebView llamada contentView que agregaste en el paso anterior.
  2. En la Ventana de propiedades, haz clic en el botón de eventos (Botón de eventos).
  3. Busca el evento NavigationFailed en la lista de eventos. En el cuadro de texto del evento, escribe "ContentView_NavigationFailed" para el nombre del método que controla el evento NavigationFailed.
  4. Presiona Entrar. El método de controlador de eventos se crea y se abre en un editor de código, de forma que puedes agregar código que se ejecutará cuando se produzca el evento.
  5. Agrega este código al controlador de eventos ContentView_NavigationFailed en la página de código subyacente.
    
                string errorString = "<p>Page could not be loaded.</p><p>Error is: " + e.WebErrorStatus.ToString() + "</p>";
                this.contentView.NavigateToString(errorString);
    
    

Para rellenar WebView, agregas tu código al controlador de eventos ItemListView_SelectionChanged. En el controlador de eventos, conviertes el elemento seleccionado en un FeedItem y obtienes la cadena de HTML de la propiedad Content. Después pasas la cadena al método NavigateToString. Si no se selecciona ningún elemento, borras WebView y pasas una cadena vacía.

BR211380.wedge(es-es,WIN.10).gifPara rellenar la vista web

  1. En el Explorador de soluciones, haz doble clic en SplitPage.xaml.cs/vb. El archivo se abre en el editor de código.
  2. Agrega este código al final del método ItemListView_SelectionChanged para rellenar la WebView con el contenido de la entrada de blog seleccionada.

    Nota  Expande la sección "Navegación de páginas lógicas" para ver el método ItemListView_SelectionChanged.

    
    
                // Add this code to populate the web view
                //  with the content of the selected blog post.
                Selector list = sender as Selector;
                FeedItem selectedItem = list.SelectedItem as FeedItem;
                if (selectedItem != null)
                {
                    this.contentView.NavigateToString(selectedItem.Content);
                }
                else
                {
                    this.contentView.NavigateToString("");
                }      
    
    
    
  3. Presiona F5 para compilar y ejecutar la aplicación.

La página dividida ahora tiene mejor aspecto y muestra la entrada de blog seleccionada en un formato más legible.

Página dividida con estilos predeterminados

Carga de DetailPage

Ahora vas a agregar contenido a la página de detalles. En DetailPage.xaml, necesitas enlazar el título TextBlock al título de la entrada de blog y agregar un control WebView para mostrar la página del blog.

BR211380.wedge(es-es,WIN.10).gifPara actualizar la página de detalles

  1. Haz doble clic en DetailPage.xaml en el Explorador de soluciones para abrirlo.
  2. Enlaza el título de página TextBlock a la propiedad Title de la publicación de blog seleccionada.
    1. Selecciona el TextBlock denominado pageTitle.
    2. En la Ventana de propiedades, haz clic en el botón de propiedades (Botón de eventos).
    3. En Común en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad Text. Se abre el menú de propiedad.
    4. En el menú de propiedad, selecciona Crear enlace de datos.... Se abrirá el cuadro de diálogo Crear enlace de datos.
    5. En el cuadro de diálogo Crear enlace de datos, selecciona Contexto de datos en la lista desplegable Tipo de enlace.
    6. Escribe "Title" en el cuadro de texto Ruta de acceso y, luego, haz clic en Aceptar.

      Nota  El mensaje en el cuadro de diálogo Crear enlace de datos dice que no se ha establecido el contexto de datos. Eso es correcto, porque estableces el contexto de datos en el código cuando ejecutas la aplicación.

  3. En el editor XAML, agrega este XAML después del elemento Grid que contenga el título de página y antes de la sección VisualStateManager.VisualStateGroups.
    
    
            <Border x:Name="contentViewBorder" BorderBrush="Gray" BorderThickness="2" 
                    Grid.Row="1" Margin="120,15,20,20">
                <WebView x:Name="contentView" 
                         NavigationFailed="ContentView_NavigationFailed"/>
            </Border>
    
    
  4. Haz doble clic en DetailPage.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  5. Agrega este código a la invalidación del método LoadState.

    Este código navega WebView al identificador uniforme de recursos (URI) de la entrada de blog y establece el DataContext de la página.

    
    
                // Add this code to navigate the web view to the selected blog post.
                string itemTitle = (string)navigationParameter;
                FeedItem feedItem = FeedDataSource.GetItem(itemTitle);
                if (feedItem != null)
                {
                    this.contentView.Navigate(feedItem.Link);
                    this.DataContext = feedItem;
                }
    
    
    
  6. Agrega este código a la clase DetailPage para controlar el evento WebView.NavigationFailed.
    
            private void ContentView_NavigationFailed(object sender, WebViewNavigationFailedEventArgs e)
            {
                string errorString = "<p>Page could not be loaded.</p><p>Error is: " + e.WebErrorStatus.ToString() + "</p>";
                this.contentView.NavigateToString(errorString);
            }
    
    
  7. Presiona F5 para compilar y ejecutar la aplicación.

    Ahora todos los datos están enlazados pero no hay modo de navegar a la página de detalles que has creado. A continuación, agregas navegación a la página de detalles.

Agregar una barra de la aplicación

La mayor parte de la navegación en la aplicación de lector de blogs tiene lugar cuando el usuario elige un elemento en la interfaz de usuario. Pero en la página de división, debes proporcionarle al usuario una forma de ir a la vista de detalle de la entrada de blog. Podrías poner un botón en alguna parte de la página, pero eso distraería la atención de la experiencia principal de la aplicación, que es leer. En lugar de ello, pones un botón en una barra de la aplicación que está oculta hasta que el usuario la necesita.

Una barra de la aplicación es un elemento de la interfaz de usuario que está oculta de manera predeterminada. Se muestra o se descarta cuando el usuario pasa un dedo desde el borde de la pantalla o interactúa con la aplicación. En ella, el usuario encontrará funciones de navegación, comandos y herramientas. Una barra de la aplicación puede aparecer en la parte superior de la página, en la parte inferior o en ambas. Te recomendamos incluir navegación en la barra de la aplicación superior, y herramientas y comandos en la barra de la aplicación inferior. Para controlar cómo y cuándo aparece y desaparece la barra de la aplicación, podemos configurar las propiedades IsSticky y IsOpen. También podemos responder a la apertura o el descarte de la barra de la aplicación mediante el control de los eventos Opened y Closed.

Para agregar una barra de la aplicación en XAML, asignas un control AppBar a la propiedad TopAppBar o a la propiedad BottomAppBar de una Page. Agregas un botón a esta barra de la aplicación superior para navegar a la página de detalles. El archivo StandardStyles.xaml contiene diversos estilos de botón de la barra de la aplicación para escenarios comunes. Usas estos estilos como guía para crear un estilo para tu botón. Pones el estilo en la sección Page.Resources de SplitPage.xaml y agregas el código XAML Page.TopAppBar inmediatamente después de la sección de recursos.

BR211380.wedge(es-es,WIN.10).gifPara agregar una barra de la aplicación

  1. Haz doble clic en SplitPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega este código XAML a la sección Page.Resources situada cerca de la parte superior de la página.

    De esta forma se agrega el recurso Style al botón de la barra de la aplicación. Encontrarás más información sobre estilos más adelante, en la sección Creación de un aspecto coherente con estilos.

    
    
        <Style x:Key="WebViewAppBarButtonStyle" TargetType="Button" 
               BasedOn="{StaticResource AppBarButtonStyle}">
            <Setter Property="AutomationProperties.AutomationId" Value="WebViewAppBarButton"/>
            <Setter Property="AutomationProperties.Name" Value="View Web Page"/>
            <Setter Property="Content" Value="&#xE12B;"/>
        </Style>
    
    
    
  3. Agrega este código XAML después de la sección Page.Resources de la página.

    Esto agrega un control AppBar a la propiedad TopAppBar de la página.

    
    <Page.TopAppBar>
       <AppBar Padding="10,0,10,0">
            <Grid>
    
                <Button HorizontalAlignment="Right" 
                        Style="{StaticResource WebViewAppBarButtonStyle}"/>
            </Grid>
        </AppBar>
    </Page.TopAppBar>
    
    
  4. Selecciona Button en la barra de la aplicación que acabas de agregar.
  5. En la Ventana de propiedades, haz clic en el botón de eventos (Botón de eventos).
  6. Busca el evento Click en la parte superior de la lista de eventos. En el cuadro de texto del evento, escribe "ViewDetail_Click" para el nombre del método que controla el evento Click.
  7. Presiona Entrar. El método de controlador de eventos se crea y se abre en un editor de código, de forma que puedes agregar código que se ejecutará cuando se produzca el evento.
  8. Agrega este código al método de controlador de eventos para controlar la navegación a la página de detalles.
    
    
                FeedItem selectedItem = this.itemListView.SelectedItem as FeedItem;
                if (selectedItem != null && this.Frame != null)
                {
                    string itemTitle = selectedItem.Title;
                    this.Frame.Navigate(typeof(DetailPage), itemTitle);
                }
    
    
    
  9. Presiona F5 para compilar y ejecutar la aplicación. Haz clic en un blog para navegar a la página de división, y selecciona una entrada de blog para leerla. Haz clic con el botón secundario en el encabezado de página para mostrar la barra de la aplicación y haz clic en el botón Show Web View para navegar a la página de detalles.

Incorporación de animaciones y transiciones

Cuando hablamos de animaciones, con frecuencia pensamos en objetos saltando por la pantalla. Pero en XAML, una animación es básicamente solo una forma de cambiar el valor de una propiedad en un objeto. Por lo tanto, las animaciones tienen más utilidad que hacer rebotar pelotas. En la aplicación de lector de blogs, usas animaciones para adaptar la interfaz de usuario a diferentes diseños y orientaciones. En la próxima sección verás esto más en profundidad pero, antes, necesitas entender cómo funcionan las animaciones.

Para usar una animación, la pones dentro de un Storyboard. Cuando Storyboard se ejecuta, la propiedad cambia según especifique la animación. Un Storyboard puede tener una o muchas animaciones. Cada animación especifica un objeto de destino, una propiedad para cambiar en ese objeto y un nuevo valor para la propiedad.

Por ejemplo, en la aplicación de lector de blogs, tienes una ListView llamada itemListView. Aquí tenemos una animación que cambia la propiedad Visibility de itemListView a Visible cuando Storyboard se ejecuta.


<Storyboard>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" 
                                   Storyboard.TargetProperty="Visibility" >
        <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
    </ObjectAnimationUsingKeyFrames>
</Storyboard>


Incorporación de animaciones de tema

Vuelve a ejecutar la aplicación y observa cómo los elementos de la interfaz de usuario se deslizan suavemente cuando se carga una página. Excepto para el control WebView que has agregado. Simplemente aparece. Windows 8 usa animaciones y transiciones para mejorar la experiencia del usuario en la interfaz de usuario. Tu intención es tener la misma experiencia en tu aplicación y que coincida con la personalidad de Windows 8. Afortunadamente, puedes usar animaciones de tema y transiciones de tema integradas en tu aplicación para que coincidan con las que se usan en Windows 8. Las encuentras en el espacio de nombres Windows.UI.Xaml.Media.Animation.

Una animación de tema es una animación preconfigurada que puedes poner dentro de Storyboard. PopInThemeAnimation hace que la vista web se deslice de derecha a izquierda cuando se carga la página. Para obtener un efecto más extremo, puedes aumentar el valor de la propiedad FromHorizontalOffset. Aquí, pones la PopInThemeAnimation en un Storyboard y la conviertes en un recurso en DetailPage.xaml. Establece el destino de la animación para que sea el Border que rodee nuestro contenido web. Esto anima el Border y todo lo que hay en él.

BR211380.wedge(es-es,WIN.10).gifPara agregar un recurso de tema

  1. Haz doble clic en DetailPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega este XAML a la sección Page.Resources.
    
    
        <Storyboard x:Name="PopInStoryboard">
            <PopInThemeAnimation  Storyboard.TargetName="contentViewBorder" 
                                  FromHorizontalOffset="400"/>
        </Storyboard>
    
    
    

En la página de código subyacente, inicias Storyboard en el método LoadState para que la animación emergente se aplique a Border cuando el usuario navegue a la página de detalles.

BR211380.wedge(es-es,WIN.10).gifPara iniciar un guión gráfico de animación

  1. Haz doble clic en DetailPage.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  2. Agrega este código al comienzo del método LoadState.
    
    
                // Run the PopInThemeAnimation 
                Windows.UI.Xaml.Media.Animation.Storyboard sb =
                    this.FindName("PopInStoryboard") as Windows.UI.Xaml.Media.Animation.Storyboard;
                if (sb != null) sb.Begin();
    
    
    
  3. Presiona F5 para compilar y ejecutar la aplicación. Navega a la página de detalles. Ahora el control WebView se desliza con los demás elementos de la interfaz de usuario cuando se carga la página dividida

Este es el código actualizado del método LoadState.


        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
            // Run the PopInThemeAnimation 
            Windows.UI.Xaml.Media.Animation.Storyboard sb =
                this.FindName("PopInStoryboard") as Windows.UI.Xaml.Media.Animation.Storyboard;
            if (sb != null) sb.Begin();

            // Add this code to navigate the web view to the selected blog post.
            string itemTitle = (string)navigationParameter;
            FeedItem feedItem = FeedDataSource.GetItem(itemTitle);
            if (feedItem != null)
            {
                this.contentView.Navigate(feedItem.Link);
                this.DataContext = feedItem;
            }
        }

También puedes seguir estos pasos y usar el mismo código para agregar esta animación al elemento contentViewBorder de SplitPage.

Para obtener más información y ver una lista completa de transiciones y animaciones temáticas, consulta el tema de inicio rápido: animar tu interfaz de usuario con animaciones de la biblioteca.

Creación de un aspecto coherente con estilos

Quieres que la aplicación de lector de blogs se parezca al sitio web de The Windows Blog. Quieres que tus usuarios puedan moverse sin problemas entre el sitio web y la aplicación. El tema oscuro predeterminado del proyecto no hace juego muy bien con el sitio web de The Windows Blog. Esto es más evidente en la página de detalles, donde cargas la página de blog real en una WebView, como se muestra aquí:

Página de detalles con tema oscuro.

Para que la aplicación tenga un aspecto coherente que podamos actualizar según sea necesario, utilizas pinceles y estilos. El Brush te permite definir un aspecto en un lugar y utilizarlo siempre que sea necesario. El Style te permite establecer valores para las propiedades de un control y volver a utilizar esa configuración en toda tu aplicación.

Antes de entrar en detalles, veamos cómo usar el pincel para establecer el color de fondo de las páginas de la aplicación. Cada página de la aplicación tiene una Grid raíz con una propiedad Background configurada para definir el color de fondo de la página. Podrías configurar el fondo de cada página uno a uno, como aquí.


<Grid Background="Blue">

Pero un modo mejor consiste en definir un Brush como recurso y usarlo para definir el color de fondo de todas las páginas. Los objetos y valores se definen como recursos para que se puedan reutilizar. Para usar un objeto o un valor como recurso, debes establecer su atributo x:Key. Utilizas esta clave para hacer referencia al recurso desde tu código XAML. Aquí se ha establecido el fondo en un recurso con la clave ApplicationPageBackgroundThemeBrush, que es un sistema definido en el archivo SolidColorBrush.


<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

Esto sirve para definir la propiedad Background de la Grid, pero normalmente te hará falta definir más de una propiedad para conseguir el aspecto que deseas. Puedes agrupar valores de configuración de cualquier número de propiedades como un Style, y aplicar dicho Style al control.

Puedes definir recursos en un archivo XAML de una página individual, en el archivo App.xaml o en un archivo XAML de diccionario de recursos independiente, como StandardStyles.xaml. El lugar donde se define el recurso determina el ámbito en el que puede usarse. Visual Studio crea el archivo StandardStyles.xaml como parte de la plantilla del proyecto y lo pone en la carpeta Common. Es un diccionario de recursos que contiene los valores, los estilos y las plantillas de datos que se usan en las plantillas de página de Visual Studio. Varias aplicaciones pueden compartir un mismo archivo XAML de diccionario de recursos y se pueden combinar varios diccionarios de recursos en una sola aplicación.

En tu aplicación de lector de blogs defines los recursos en App.xaml para que estén disponibles en toda la aplicación. También tienes algunos recursos definidos en el archivo XAML para páginas individuales. Estos recursos se encuentran disponibles solo en la página donde se definen. Si se definen recursos con la misma clave en App.xaml y en una página, el recurso de la página invalida el recurso en App.xaml. Del mismo modo, un recurso definido en App.xaml invalidará un recurso definido con la misma clave en un archivo de diccionario de recursos independiente. Para obtener más información, consulta Inicio rápido: controles de estilo.

Ahora veamos un ejemplo de uso de Style en la aplicación. El aspecto de las páginas de la plantilla está definido por un estilo con la clave LayoutRootStyle. La definición de Style está en el archivo StandardStyles.xaml.


<Grid Style="{StaticResource LayoutRootStyle}">



    <!-- Page layout roots typically use entrance animations  
         and a theme-appropriate background color -->

    <Style x:Key="LayoutRootStyle" TargetType="Panel">
        <Setter Property="Background" 
                Value="{StaticResource ApplicationPageBackgroundThemeBrush}"/>
        <Setter Property="ChildrenTransitions">
            <Setter.Value>
                <TransitionCollection>
                    <EntranceThemeTransition/>
                </TransitionCollection>
            </Setter.Value>
        </Setter>
    </Style>

En la definición de Style, necesitas un atributo TargetType y una colección de uno o más Setter. Estableces el TargetType en una cadena que especifica el tipo al cual se aplica el Style, en este caso, un elemento Panel. Si intentas aplicar un Style a un control que no coincide con el atributo TargetType, se produce una excepción. Cada elemento Setter requiere una Property y un Value. Esta configuración de las propiedades indica a qué propiedades del control se aplica la configuración, y el valor que se fija para esa propiedad.

Para cambiar el Background de tus páginas, debes reemplazar el ApplicationPageBackgroundThemeBrush con tu propio pincel personalizado. Para tu pincel personalizado, usas el Color #FF0A2562, que es un azul bonito que combina bien con los colores del sitio http://windowsteamblog.com. Para reemplazar el pincel del tema del sistema, creas un nuevo Style que se base en LayoutRootStyle y cambias la propiedad Background ahí. Así es como defines un estilo nuevo para la raíz de diseño.

BR211380.wedge(es-es,WIN.10).gifPara cambiar el fondo de página

  1. Haz doble clic en App.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega estas definiciones de pincel y de estilo en el ResourceDictionary con tus otros recursos específicos de la aplicación, después del recurso feedDataSource.
    
    
                <SolidColorBrush x:Key="WindowsBlogBackgroundBrush" 
                                        Color="#FF0A2562"/>
                <Style x:Key="WindowsBlogLayoutRootStyle" 
                               TargetType="Panel" 
                               BasedOn="{StaticResource LayoutRootStyle}">
                    <Setter Property="Background" 
                                    Value="{StaticResource WindowsBlogBackgroundBrush}"/>
                </Style>
    
    

Este es el código XAML completo para la sección ResourceDictionary de App.xaml.


    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!-- 
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->
                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <local:FeedDataSource x:Key="feedDataSource"/>

            <SolidColorBrush x:Key="WindowsBlogBackgroundBrush" 
                                    Color="#FF0A2562"/>
            <Style x:Key="WindowsBlogLayoutRootStyle" 
                           TargetType="Panel" 
                           BasedOn="{StaticResource LayoutRootStyle}">
                <Setter Property="Background" 
                                Value="{StaticResource WindowsBlogBackgroundBrush}"/>
            </Style>
        </ResourceDictionary>
    </Application.Resources>

Importante  Porque basaste un estilo en un estilo de sistema en StandardStyles.xaml, el ResourceDictionary que incluye StandardStyles.xaml tiene que declararse en el XAML antes de tu estilo que se basa en él. Si no se hace así, el analizador de XAML no podrá encontrar el LayoutRootStyle en que se basa tu estilo.

La línea BasedOn="{StaticResource LayoutRootStyle}" indica al nuevo Style que herede de LayoutRootStyle todas las propiedades que no establecimos de manera explícita. Nuestro nuevo Style es como el estilo predeterminado, pero con un fondo azul, y puedes usarlo para todas las páginas.

BR211380.wedge(es-es,WIN.10).gifPara cambiar el fondo de cada página

  1. Haz doble clic en ItemsPage.xaml en el Explorador de soluciones para abrirlo.
  2. Selecciona el diseño raíz de la página Grid.
  3. En Varios en el panel Propiedades, busca la propiedad Style.
  4. Haz clic en el marcador de propiedades que hay al lado de la propiedad Style para abrir el menú.
  5. En el menú, selecciona Recurso local > WindowsBlogLayoutRootStyle.
  6. Repite los pasos 2 a 5 para SplitPage.xaml y DetailPage.xaml.

    El XAML del elemento Grid raíz de cada página ahora tiene este aspecto.

    
    
     <Grid Style="{StaticResource WindowsBlogLayoutRootStyle}">
    
    
  7. Presiona F5 para compilar y ejecutar la aplicación, y ver las páginas azules.

Para que la aplicación tenga el aspecto del sitio web de The Windows Blog, utilizas las plantillas de datos personalizadas además de controles Brush y Style. Empecemos usando plantillas para aplicar formato a los elementos de lista en la página dividida.

Formato de datos con una plantilla de datos

En SplitPage.xaml, la apariencia de los elementos en itemListView se define en la Standard130ItemTemplate, que se encuentra en StandardStyles.xaml. La plantilla de elemento se asigna en esta línea de XAML: ItemTemplate="{StaticResource Standard130ItemTemplate}". Para ver el efecto de esta plantilla, puedes quitarla y ver la apariencia de la lista sin ella.

Lista enlazada que muestra el título.

Tienes la ListView enlazada a la propiedad Items del objeto FeedData, por lo que tenemos los datos correctos. Pero, cuando ejecutas la aplicación de este modo, ListView no sabe qué mostrar y llama a ToString en el objeto al que está enlazada. El resultado es una lista de cadenas "WindowsBlogReader.FeedItem" como la que viste antes. Está claro que esto no es lo que quieres mostrar.

Para mejorarlo un poco, estableces la propiedad DisplayMemberPath en la ListView. Esto indica a la vista de lista que llame a ToString en la propiedad especificada del objeto enlazado, en lugar de en el objeto en sí. Si estableces DisplayMemberPath=Title, la ListView muestra una lista de títulos de entradas de blog.

He aquí el XAML de ListView con la DisplayMemberPath establecida en la propiedad Title.


<ListView
    x:Name="itemListView"
    AutomationProperties.AutomationId="ItemsListView"
    AutomationProperties.Name="Items"
    TabIndex="1"
    Grid.Row="1"
    Margin="-10,-10,0,0"
    Padding="120,0,0,60"
    ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
    IsSwipeEnabled="False"
    SelectionChanged="ItemListView_SelectionChanged"
    DisplayMemberPath="Title"/>

Cuando ejecutas la aplicación, los elementos de lista tienen ahora este aspecto. Esto se parece más a lo que quieres mostrar.

Lista enlazada que muestra el título.

Pero lo que en realidad quieres es mostrar el título, el autor y la fecha de publicación de cada entrada de la lista. Para mostrar más de una propiedad del elemento de datos, defines una plantilla que le dice a ListView exactamente cómo quieres que se muestren los datos. Los controles para ver colecciones de elementos de datos se derivan de la clase ItemsControl. Estos controles tienen una propiedad ItemTemplate a la cual podemos asignar una DataTemplate. DataTemplate define el aspecto de tus datos.

Importante  No puedes usar DisplayMemberPath y ItemTemplate al mismo tiempo. Cuando establezcas la propiedad ItemTemplate, asegúrate de quitar el valor DisplayMemberPath.

La plantilla de elemento predeterminada está cerca de lo que quieres mostrar. Usémosla como el punto de inicio para tu plantilla.

BR211380.wedge(es-es,WIN.10).gifPara crear un nuevo elemento ItemTemplate

  1. En el Explorador de soluciones, abre SplitPage.xaml.
  2. Selecciona la ListView denominada "itemListView".
  3. En Varios en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad ItemTemplate. Se abre el menú de propiedad.

    Nota  El marcador de propiedad es el símbolo de cuadro pequeño situado a la derecha de cada valor de propiedad. El marcador de propiedad ItemTemplate de color verde indica que se ha establecido en un recurso.

  4. En el menú de propiedad, selecciona Convertir en nuevo recurso.... Se abrirá el cuadro de diálogo Crear recurso DataTemplate.
  5. En el cuadro de diálogo Crear recurso DataTemplate, escribe "DefaultListItemTemplate" en el cuadro de texto Nombre (clave).

    Asegúrate de que la opción Definir en esté establecida en Este documento > "LayoutAwarePage:pageRoot".

    Nota  La vista Diseño de la página XAML debe estarse mostrando en Visual Studio. Si solamente se muestra el editor XAML, algunas opciones están deshabilitadas.

  6. Haz clic en Aceptar.

    Una nueva DataTemplate se crea en la sección Resources de SplitPage.xaml. Esta es una copia del recurso Standard130ItemTemplate que puedes modificar. La propiedad ItemTemplate de itemListView también se actualiza para usar DefaultListItemTemplate.

Definir la parte de la interfaz de usuario en DataTemplate es igual que definir cualquier otra interfaz de usuario. Esta plantilla tiene una cuadrícula con 2 columnas. La primera cuadrícula tiene un borde cuadrado con una imagen de marcador. La segunda columna tiene un StackPanel con tres TextBlock apilados unos sobre otros. De manera predeterminada, las propiedades de Text de los elementos deTextBlock están vinculadas a las propiedades del origen de datos de muestra usado en las plantillas de Visual Studio. El DataContext predeterminado para estos enlaces es el objeto que aparece en ListView, que es un FeedItem. Puedes actualizar los enlaces para mostrar las propiedades Title, Author y PubDate del FeedItem.

He aquí el XAML para la plantilla de datos con los enlaces actualizados.


        <DataTemplate x:Key="DefaultListItemTemplate">
            <Grid Height="110" Margin="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" 
                        Width="110" Height="110">
                    <Image Source="{Binding Image}" Stretch="UniformToFill" 
                           AutomationProperties.Name="{Binding Title}"/>
                </Border>
                <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,0,0,0">
                    <TextBlock Text="{Binding Title}" 
                               Style="{StaticResource TitleTextStyle}" TextWrapping="NoWrap"/>
                    <TextBlock Text="{Binding Author}" 
																															Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap"/>
                    <TextBlock Text="{Binding PubDate}" 
																															Style="{StaticResource BodyTextStyle}" MaxHeight="60"/>
                </StackPanel>
            </Grid>
        </DataTemplate>

Así se ven las vistas de lista al ejecutar la aplicación.

Lista enlazada con una plantilla de datos.

Ahora la lista muestra los datos que quieres, pero no refleja la personalización de marca del sitio web de The Windows Blog, como ves aquí.

Lista de publicaciones de blog de Windows.

Para hacer que la vista de lista tenga una apariencia más similar al sitio web, usas un ContentControl y ControlTemplate para mostrar la fecha en un bloque verde y actualiza la apariencia del título TextBlock para mostrar los títulos en naranja. También usas un convertidor de valores para aplicar formato a la fecha de la manera en que lo desees.

Formato de datos con un convertidor de valores

En la DataTemplate de ItemListView, enlazas la propiedad PubDate, que es de tipo DateTime, a la propiedad TextBlock.Text. El motor de enlace convierte automáticamente la PubDate de tipo DateTime en cadena. Pero la conversión automática muestra tanto la fecha como la hora, y quieres mostrar solo la fecha. Para arreglar esto, puedes crear tu propio convertidor de valores que convierte DateTime en una cadena, y en él puedes dar el formato que quieras a la cadena.

Para crear un convertidor de valores, creas una clase que implementa la interfaz IValueConverter y después se implementan los métodos Convert y ConvertBack. Los convertidores pueden cambiar datos de un tipo a otro, traducir datos en función de la información cultural o modificar otros aspectos de la presentación.

Los métodos Convert y ConvertBack también permiten especificar un parámetro para que puedas usar la misma instancia del convertidor con distintas opciones. En este ejemplo, tienes un convertidor de formato que genera distintos formatos de fecha en función del parámetro de entrada. Puedes utilizar el ConverterParameter de la clase Binding para pasar un parámetro como argumento a los métodos Convert y ConvertBack. Usas esta característica para aplicar formato a la fecha para mostrarla en el formato de bloque usado en el sitio web del blog.

Aquí, creas un convertidor de datos que convierte el valor de fecha especificado y le da formato para que muestre solo el día, el mes y el año.

BR211380.wedge(es-es,WIN.10).gifPara agregar un convertidor de valores

  1. Selecciona Proyecto > Agregar clase. Se abre el cuadro de diálogo Nuevo elemento.
  2. Escribe DateConverter como nombre del archivo de clase.
  3. Haz clic en Agregar. Se crea el archivo de clase DateConverter.cs/vb.
  4. Copia este código en el archivo DateConverter.cs/vb. Reemplaza todo el código existente en el archivo.
    
    
    using System;
    using Windows.Globalization.DateTimeFormatting;
    
    namespace WindowsBlogReader
    {
        public class DateConverter : Windows.UI.Xaml.Data.IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, string culture)
            {
                if (value == null)
                    throw new ArgumentNullException("value", "Value cannot be null.");
    
                if (!typeof(DateTime).Equals(value.GetType()))
                    throw new ArgumentException("Value must be of type DateTime.", "value");
                
                DateTime dt = (DateTime)value;
    
                if (parameter == null)
                {
                    // Date "7/27/2011 9:30:59 AM" returns "7/27/2011"
                    return DateTimeFormatter.ShortDate.Format(dt);
                }           
                else if ((string)parameter == "day")
                {
                    // Date "7/27/2011 9:30:59 AM" returns "27"
                    DateTimeFormatter dateFormatter = new DateTimeFormatter("{day.integer(2)}");
                    return dateFormatter.Format(dt);
                }
                else if ((string)parameter == "month")
                {
                    // Date "7/27/2011 9:30:59 AM" returns "JUL"
                    DateTimeFormatter dateFormatter = new DateTimeFormatter("{month.abbreviated(3)}");
                    return dateFormatter.Format(dt).ToUpper();
                }
                else if ((string)parameter == "year")
                {
                    // Date "7/27/2011 9:30:59 AM" returns "2011"
                    DateTimeFormatter dateFormatter = new DateTimeFormatter("{year.full}");
                    return dateFormatter.Format(dt);
                }
                else
                {
                    // Requested format is unknown. Return in the original format.
                    return dt.ToString();
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, string culture)
            {
                string strValue = value as string;
                DateTime resultDateTime;
                if (DateTime.TryParse(strValue, out resultDateTime))
                {
                    return resultDateTime;
                }
                return Windows.UI.Xaml.DependencyProperty.UnsetValue;
            }
        }
    }
    
    
    
  5. Haz clic en Compilar > Compilar solución para asegurarte de que la solución se genera sin errores.

Para poder usar la clase DateConverter, debes declarar una instancia de esta en XAML. Lo declaras como un recurso de la aplicación con la clave dateConverter en App.xaml. Al declararla aquí, la estas poniendo a disposición de cualquier página de tu aplicación.

BR211380.wedge(es-es,WIN.10).gifPara agregar el recurso de la aplicación dateConverter

  1. Haz doble clic en App.xaml en el Explorador de soluciones para abrirlo.
  2. Agrega la declaración de recurso, <local:DateConverter x:Key="dateConverter" />, a ResourceDictionary después del recurso feedDataSource.

Ahora puedes usar el DateConverter en los enlaces del bloque de fechas que creas a continuación. Con el convertidor agregado, el motor de enlace usa tu DateConverter personalizado para cambiar DateTime a una cadena. A la cadena que devuelve se le aplica el formato de la forma deseada, solo con el día, mes y año.

En App.xaml, agregas una ControlTemplate que define un bloque cuadrado donde aparece la fecha. Al establecer esto en App.xaml, puedes usarlo tanto en ItemsPage.xaml como en SplitPage.xaml.

BR211380.wedge(es-es,WIN.10).gifPara agregar una plantilla de control a App.xaml

  1. Haz doble clic en App.xaml en el Explorador de soluciones para abrirlo.
  2. Agrega este XAML en el ResourceDictionary con tus otros recursos específicos de la aplicación, después del recurso WindowsBlogLayoutRootStyle.
    
    
    <ControlTemplate x:Key="DateBlockTemplate">
        <Canvas Height="86" Width="86"  Margin="8,8,0,8" HorizontalAlignment="Left" VerticalAlignment="Top">
            <TextBlock TextTrimming="WordEllipsis" TextWrapping="NoWrap" 
                       Width="Auto" Height="Auto" Margin="8,0,4,0" 
                       FontSize="32" FontWeight="Bold">
                <TextBlock.Text>
                    <Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="month"  />
                </TextBlock.Text>
            </TextBlock>
    
            <TextBlock TextTrimming="WordEllipsis" TextWrapping="Wrap" 
                       Width="40" Height="Auto" Margin="8,0,0,0" 
                       FontSize="34" FontWeight="Bold" Canvas.Top="36">
                <TextBlock.Text>
                    <Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="day"  />
                </TextBlock.Text>
            </TextBlock>
            <Line Stroke="White" StrokeThickness="2" X1="54" Y1="46" X2="54" Y2="80" />
    
            <TextBlock TextWrapping="Wrap" 
                Width="20" Height="Auto" 
                FontSize="{StaticResource ControlContentThemeFontSize}" Canvas.Top="42" Canvas.Left="60">
                <TextBlock.Text>
                    <Binding Path="PubDate" Converter="{StaticResource dateConverter}" ConverterParameter="year"  />
                </TextBlock.Text>
            </TextBlock>
        </Canvas>
    </ControlTemplate>
    
    

Ahora puedes usar esta plantilla de control en SplitPage.xaml para actualizar la apariencia de los elementos de lista en la vista predeterminada.

BR211380.wedge(es-es,WIN.10).gifPara usar la plantilla de control en SplitPage.xaml

  1. Haz doble clic en SplitPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor de XAML, busca el recurso DefaultListItemTemplate que creaste anteriormente.
  3. Reemplaza el XAML para el elemento Border con este XAML.
    
                    <Border Background="#FF6BBD46" Width="110" Height="110">
                        <ContentControl Template="{StaticResource DateBlockTemplate}" />
                    </Border>
    
    
  4. Reemplaza el XAML para los tres elementos deTextBlocken el elemento StackPanelcon este XAML.
    
                        <TextBlock Text="{Binding Title}" FontSize="26.667" TextWrapping="Wrap"
                                   MaxHeight="72" Foreground="#FFFE5815" />
                        <TextBlock Text="{Binding Author}" FontSize="18.667" />
    
    

He aquí el XAML actualizado para la plantilla de datos.



        <DataTemplate x:Key="DefaultListItemTemplate">
            <Grid Height="110" Margin="6">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Border Background="#FF6BBD46" Width="110" Height="110">
                    <ContentControl Template="{StaticResource DateBlockTemplate}" />
                </Border>
                <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,0,0,0">
                    <TextBlock Text="{Binding Title}" FontSize="26.667" TextWrapping="Wrap"
                               MaxHeight="72" Foreground="#FFFE5815" />
                    <TextBlock Text="{Binding Author}" FontSize="18.667" />
                </StackPanel>
            </Grid>
        </DataTemplate>

Importante  Esta plantilla se usa en la vista horizontal de pantalla completa predeterminada. Si tu resolución de pantalla es menor que 1366 píxeles de ancho, la página dividida usa el estado de visualización FilledOrNarrow y no verás esta plantilla en la vista de lista. Para ver esta plantilla, ejecuta la aplicación en el simulador de Visual Studio con una resolución de 1366 x 768 o superior. Si quieres más información sobre cómo probar la aplicación en el simulador, consulta el tema sobre cómo ejecutar aplicaciones de la Tienda Windows desde Visual Studio.

Para finalizar la aplicación de estilos a la página dividida, debes cambiar el color de fondo de la barra de la aplicación y el color del elemento seleccionado en la vista de lista.

BR211380.wedge(es-es,WIN.10).gifPara actualizar el fondo de la barra de la aplicación

  1. En SplitPage.xaml, selecciona el control AppBar.
  2. En Pincel en el panel Propiedades, o en el editor de XAML, establece la propiedad Background en "#F20A2562".
    
    <AppBar Padding="10,0,10,0" Background="#F20A2562">
    
    

De manera predeterminada, el elemento seleccionado en la vista de lista tiene un fondo púrpura. Reemplazas los pinceles de temas de la vista de lista predeterminados para hacer que el elemento seleccionado sea azul. Para reemplazar los pinceles de temas integrados, defines un pincel con la misma clave en App.xaml y le das un nuevo valor.

BR211380.wedge(es-es,WIN.10).gifPara actualizar los colores de la vista de lista

  1. Haz doble clic en App.xaml en el Explorador de soluciones para abrirlo.
  2. Agrega este XAML en el ResourceDictionary después de tus otros recursos específicos de la aplicación.
    
    
    <SolidColorBrush x:Key="ListViewItemSelectedBackgroundThemeBrush" Color="#FF465985"/>
    <SolidColorBrush x:Key="ListViewItemSelectedPointerOverBackgroundThemeBrush" Color="#FF384A72"/>
    <SolidColorBrush x:Key="ListViewItemSelectedPointerOverBorderThemeBrush" Color="#FF384A72" />
    
    

Para finalizar la aplicación de estilos a la aplicación, aplicas estilos similares a la página de los elementos. En ItemsPage.xaml, agregas estos recursos para definir el aspecto de los elementos de la cuadrícula en la vista predeterminada.

BR211380.wedge(es-es,WIN.10).gifPara aplicar estilo a ItemsPage.xaml

  1. Haz doble clic en ItemsPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega este XAML a la sección Page.Resources después del recurso AppName.
    
    
            <!-- light blue -->
            <SolidColorBrush x:Key="BlockBackgroundBrush" Color="#FF557EB9"/>
    
            <!-- Grid Styles -->
            <Style x:Key="GridTitleTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}">
                <Setter Property="FontSize" Value="26.667"/>
                <Setter Property="Margin" Value="12,0,12,2"/>
            </Style>
    
            <Style x:Key="GridDescriptionTextStyle" TargetType="TextBlock" BasedOn="{StaticResource BasicTextStyle}">
                <Setter Property="VerticalAlignment" Value="Bottom"/>
                <Setter Property="Margin" Value="12,0,12,60"/>
            </Style>
    
            <DataTemplate x:Key="DefaultGridItemTemplate">
                <Grid HorizontalAlignment="Left" Width="250" Height="250">
                    <Border Background="{StaticResource BlockBackgroundBrush}" />
                    <TextBlock Text="{Binding Title}" Style="{StaticResource GridTitleTextStyle}"/>
                    <TextBlock Text="{Binding Description}" Style="{StaticResource GridDescriptionTextStyle}" />
                    <StackPanel VerticalAlignment="Bottom" Orientation="Horizontal"
                            Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
                        <TextBlock Text="Last Updated" Margin="12,4,0,8" Height="42"/>
                        <TextBlock Text="{Binding PubDate, Converter={StaticResource dateConverter}}" Margin="12,4,12,8" />
                    </StackPanel>
                </Grid>
            </DataTemplate>
    
    
  3. Selecciona el control GridView denominado itemGridView.
  4. En Varios en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad ItemTemplate. Se abre el menú de propiedad.
  5. En el menú, selecciona Recurso local > DefaultGridItemTemplate.

    Nota  La vista Diseño de la página XAML debe estarse mostrando en Visual Studio. Si solamente se muestra el editor XAML, no se enumeran los recursos de página locales.

    Este es el código XAML actualizado y completo para itemGridView.

    
    
            <!-- Horizontal scrolling grid used in most view states -->
            <GridView
                x:Name="itemGridView"
                AutomationProperties.AutomationId="ItemsGridView"
                AutomationProperties.Name="Items"
                TabIndex="1"
                Grid.RowSpan="2"
                Padding="116,136,116,46"
                ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
                
                ItemTemplate="{StaticResource DefaultGridItemTemplate}"
                
                SelectionMode="None"
                IsSwipeEnabled="false" 
                IsItemClickEnabled="True" 
                ItemClick="ItemView_ItemClick"/>
    
    
  6. Presiona F5 para compilar y ejecutar la aplicación. La página de elementos ahora usa la nueva plantilla.

Con tus estilos aplicados, la aplicación se asemeja al aspecto del sitio web de The Windows Blog:

Página de colección con estilo.

Página de división con estilo.

Página de detalles con estilo.

Puedes usar estilos y basarlos en otros estilos para definir y aplicar rápidamente aspectos distintos a la aplicación. En la sección siguiente, combinas lo que sabes sobre animaciones y estilos para que la aplicación se adapte rápidamente a los diferentes diseños y orientaciones mientras se ejecuta.

Adaptación a distintos diseños

Nota  En esta sección, aplicas los conceptos descritos en Parte 3: Navegación, diseño y vistas. Para obtener más información sobre cómo adaptar la interfaz de usuario a las distintas vistas y para conocer el soporte de herramientas disponible, consulta la Parte 3.

Normalmente, las aplicaciones están diseñadas para verse en pantalla completa con orientación horizontal. Pero una aplicación de la Tienda Windows debe adaptarse a orientaciones y diseños diferentes. Específicamente, debe admitir ambas orientaciones, horizontal y vertical. En la orientación horizontal, debe admitir los diseños de pantalla completa, rellena y acoplada.

Sugerencia  Para probar la aplicación en diferentes orientaciones y resoluciones, puedes ejecutarla en el simulador. Para ejecutar tu aplicación de la Tienda Windows en el simulador, selecciona Simulador de la lista desplegable situada junto al botón Iniciar depuración en la barra de herramientas Estándar. Si quieres más información sobre el simulador, consulta el tema sobre cómo ejecutar aplicaciones de la Tienda Windows desde Visual Studio.

Las plantillas de Visual Studio incluyen código que controla los cambios en el estado de visualización. Este código se incluye en el archivo LayoutAwarePage.cs/vb y asigna el estado de la aplicación a estados visuales definidos en tu código XAML. Como ya se incluye la lógica del diseño de página, solo es necesario que proporciones las vistas que se usarán en cada uno de los estados visuales de la página.

Para realizar transiciones entre las distintas vistas con XAML, usas VisualStateManager para definir VisualState diferentes para tu aplicación. Aquí ves un VisualStateGroup definido en ItemsPage.xaml. Este grupo tiene 4 VisualState denominados FullScreenLandscape, Filled, FullScreenPortrait y Snapped. No se pueden utilizar VisualState distintos del mismo VisualStateGroup al mismo tiempo. Cada VisualState tiene animaciones que indican a la aplicación lo que debe cambiar desde la línea base que se especifica en el código XAML de la interfaz de usuario.


<!--App Orientation States-->
  <VisualStateManager.VisualStateGroups>
     <VisualStateGroup x:Name="ApplicationViewStates">
        <VisualState x:Name="FullScreenLandscape" />
        <VisualState x:Name="Filled"> ... </VisualState>
        <VisualState x:Name="FullScreenPortrait"> ... </VisualState>
        <VisualState x:Name="Snapped"> ... </VisualState>
    </VisualStateGroup>
 </VisualStateManager.VisualStateGroups>

Usas el estado FullScreenLandscape cuando la aplicación está en pantalla completa en la orientación horizontal. Como diseñas una interfaz de usuario predeterminada para esta vista, no se necesitan cambios y este es tan solo un VisualState vacío.

Usas el estado Filled cuando el usuario tiene otra aplicación acoplada en un lado de la pantalla. En este caso, la página de vista de elementos se aparta y no se necesitan cambios. Este también es un VisualState vacío.

Usas el estado FullScreenPortrait cuando la aplicación se gira de la orientación horizontal a vertical. En este estado visual, tienes dos animaciones. Una de ellas cambia el estilo usado en el botón Atrás y la otra cambia el margen de itemGridView para que todo se ajuste mejor en la pantalla.


<!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" 
                                       Storyboard.TargetProperty="Style">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" 
                                       Storyboard.TargetProperty="Padding">
            <DiscreteObjectKeyFrame KeyTime="0" Value="96,136,86,56"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>


Usas el estado Snapped cuando el usuario tiene dos aplicaciones abiertas y tu aplicación es la más estrecha de las dos. En este estado, tu aplicación solo tiene 320 píxeles independientes del dispositivo (DIP), de modo que debes hacer cambios más acusados en el diseño. En el código XAML de la interfaz de usuario de la página de elementos, se definen tanto una GridView como una ListView y enlazan con la colección de datos. De manera predeterminada, se muestra itemGridView e itemListView se contrae. En el estado Snapped, tienes 4 animaciones que contraen itemGridView, muestran itemListView y cambian el Style del botón Atrás y el título de la página para hacerlos más pequeños.


<!--
    The back button and title have different styles when snapped, and the list representation is substituted
    for the grid displayed in all other view states
-->
<VisualState x:Name="Snapped">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" 
                                       Storyboard.TargetProperty="Style">
            <DiscreteObjectKeyFrame KeyTime="0" 
                                    Value="{StaticResource SnappedBackButtonStyle}"/>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" 
                                       Storyboard.TargetProperty="Style">
            <DiscreteObjectKeyFrame KeyTime="0" 
                                    Value="{StaticResource SnappedPageHeaderTextStyle}"/>
        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" 
                                       Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
        </ObjectAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView"
                                       Storyboard.TargetProperty="Visibility">
            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

En la sección Creación de un aspecto coherente con estilos de este tutorial, creas estilos y plantillas para dar un aspecto personalizado a la aplicación. La vista horizontal predeterminada usa estos estilos y plantillas. Para mantener el aspecto personalizado en distintas vistas, también debes crear plantillas y estilos personalizados para esas vistas.

En ItemsPage.xaml, creas una nueva plantilla de datos para los elementos de cuadrícula. También debes proporcionar una nueva plantilla de datos para los elementos de lista que se muestran en la vista Snapped. Llamas a esta plantilla NarrowListItemTemplate y la agregas a la sección de recursos de ItemsPage.xaml, justo después del recurso DefaultGridItemTemplate.

BR211380.wedge(es-es,WIN.10).gifPara agregar una plantilla para la vista acoplada

  1. Haz doble clic en ItemsPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega este XAML a la sección Page.Resources después del recurso DefaultGridItemTemplate.
    
            <!-- Used in Snapped view -->
            <DataTemplate x:Key="NarrowListItemTemplate">
                <Grid Height="80">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Border Background="{StaticResource BlockBackgroundBrush}" Width="80" Height="80" />
                    <ContentControl Template="{StaticResource DateBlockTemplate}" Margin="-12,-12,0,0"/>
                    <StackPanel Grid.Column="1" HorizontalAlignment="Left" Margin="12,8,0,0">
                        <TextBlock Text="{Binding Title}" MaxHeight="56" TextWrapping="Wrap"/>
                    </StackPanel>
                </Grid>
            </DataTemplate>
    
    
  3. Selecciona el control ListView denominado itemListView.
  4. En Varios en el panel Propiedades, haz clic en el marcador de propiedad de la propiedad ItemTemplate. Se abre el menú de propiedad.
  5. En el menú, selecciona Recurso local > NarrowListItemTemplate.

    He aquí el XAML actualizado completo para itemListView.

    
    
            <!-- Vertical scrolling list only used when snapped -->
            <ListView
                x:Name="itemListView"
                AutomationProperties.AutomationId="ItemsListView"
                AutomationProperties.Name="Items"
                TabIndex="1"
                Grid.Row="1"
                Visibility="Collapsed"
                Margin="0,-10,0,0"
                Padding="10,0,0,60"
                ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
                ItemTemplate="{StaticResource NarrowListItemTemplate}"
                SelectionMode="None"
                IsSwipeEnabled="false" 
                IsItemClickEnabled="True" 
                ItemClick="ItemView_ItemClick"/>
    
    

En ItemsPage, tienes tanto una GridView como una ListView, y aplicas las plantillas en el XAML predeterminado. Muestras la GridView de la vista predeterminada. Cuando se acopla la aplicación, reemplazas la cuadrícula con la ListView mediante VisualStateManager para cambiar las propiedades Visibility de ambas vistas.

En SplitPage, usas otro método para cambiar la interfaz de usuario cuando cambia la vista. Tienes una única ListView que muestras en todas las vistas. Para cambiar su aspecto cuando cambia la vista, usas VisualStateManager para aplicar una nueva plantilla a ListView.

En SplitPage.xaml, creas una plantilla ListView similar que se usa en las vistas Filled y Snapped, y en la vista FullScreenLandscape, si el ancho de pantalla es inferior a 1.366 DIP. También llamas a esta plantilla NarrowListItemTemplate y la agregas a la sección de recursos de SplitPage.xaml, justo después del recurso DefaultListItemTemplate.

BR211380.wedge(es-es,WIN.10).gifPara agregar una plantilla estrecha

  1. Haz doble clic en SplitPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el editor XAML, agrega este XAML a la sección Page.Resources después del recurso DefaultListItemTemplate.
    
    
            <!-- green -->
            <SolidColorBrush x:Key="BlockBackgroundBrush" Color="#FF6BBD46"/>
    
            <!-- Used in Filled and Snapped views -->
            <DataTemplate x:Key="NarrowListItemTemplate">
                <Grid Height="80">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Border Background="{StaticResource BlockBackgroundBrush}" 
                            Width="80" Height="80"/>
                    <ContentControl Template="{StaticResource DateBlockTemplate}" 
                                    Margin="-12,-12,0,0"/>
                    <StackPanel Grid.Column="1" HorizontalAlignment="Left" 
                                Margin="12,8,0,0">
                        <TextBlock Text="{Binding Title}" MaxHeight="56" 
                                   Foreground="#FFFE5815" TextWrapping="Wrap"/>
                        <TextBlock Text="{Binding Author}" FontSize="12" />
                    </StackPanel>
                </Grid>
            </DataTemplate>
    
    

Para usar esta plantilla de datos, actualizas los estados visuales en los que se utiliza.

BR211380.wedge(es-es,WIN.10).gifPara actualizar los estado visuales

  1. En el código XAML de los estados visuales FilledOrNarrow y Snapped, buscamos la animación destinada a la propiedad ItemTemplate de itemListView.

    Sugerencia  Presiona Ctrl+F para abrir el cuadro Búsqueda rápida y busca "Standard80ItemTemplate" si tienes problemas para encontrarlo.

  2. Cambia el valor para usar el recurso NarrowListItemTemplate, del siguiente modo: Value="{StaticResource NarrowListItemTemplate}".

    Usas tu plantilla personalizada en lugar del recurso Standard80ItemTemplate predeterminado.

Este es el código XAML actualizado para las animaciones.



<VisualState x:Name="FilledOrNarrow">
    <Storyboard>
    ....
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="ItemTemplate">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource NarrowListItemTemplate}"/>
        </ObjectAnimationUsingKeyFrames>
    ....
    </Storyboard>
</VisualState>
...
<VisualState x:Name="Snapped">
    <Storyboard>
    ....
        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="ItemTemplate">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource NarrowListItemTemplate}"/>
        </ObjectAnimationUsingKeyFrames>
    ....
    </Storyboard>
</VisualState>

También reemplazas la sección de detalles de elemento de la página de división con tu propia sección de detalles que usa una WebView. Como has realizado este cambio, algunas animaciones del estado visual Snapped_Detail tienen como destino elementos que ya no están presentes. Esto provocará errores cuando uses este estado visual, de modo que es necesario que las quites.

BR211380.wedge(es-es,WIN.10).gifPara quitar las animaciones que no se usan

  • En SplitPage.xaml, elimina estas animaciones del estado visual Snapped_Detail.
    
    
    <VisualState x:Name="Snapped_Detail">
        <Storyboard>
        ...
            <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailTitlePanel" Storyboard.TargetProperty="(Grid.Row)">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailTitlePanel" Storyboard.TargetProperty="(Grid.Column)">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
                </ObjectAnimationUsingKeyFrames>-->
       ...
            <!--<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemSubtitle" Storyboard.TargetProperty="Style">
                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource CaptionTextStyle}"/>
                </ObjectAnimationUsingKeyFrames>-->
        </Storyboard>
    </VisualState>
    
    

Cuando selecciona un blog y navegas a la página dividida de la vista acoplada, esperas que se muestre la lista de entrada del blog. En lugar de ello se muestra el texto de la primera entrada de blog, ya que se selecciona de manera predeterminada. Para cambiar este comportamiento, debes asegurarte de que no hay nada seleccionado cuando navegas a la página dividida en la vista acoplada.

BR211380.wedge(es-es,WIN.10).gifPara anular la selección del primer elemento

  1. Haz doble clic en SplitPage.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  2. En el método LoadState, busca este bloque de código.
    
                if (pageState == null)
                {
                    // When this is a new page, select the first item automatically unless logical page
                    // navigation is being used (see the logical page navigation #region below.)
                    if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
                    {
                        this.itemsViewSource.View.MoveCurrentToFirst();
                    }
                }
    
    
  3. Agrega la cláusula else como se muestra aquí. La llamada MoveCurrentToPosition(-1) anula la selección del elemento actual.
    
                if (pageState == null)
                {
                    // When this is a new page, select the first item automatically unless logical page
                    // navigation is being used (see the logical page navigation #region below.)
                    if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
                    {
                        this.itemsViewSource.View.MoveCurrentToFirst();
                    }
                    else
                    {
                        this.itemsViewSource.View.MoveCurrentToPosition(-1);
                    }
                }
    
    

En DetailPage.xaml, simplemente debes ajustar el margen de la WebView en la vista Snapped para usar todo el espacio disponible.

BR211380.wedge(es-es,WIN.10).gifPara actualizar DetailPage.xaml

  1. Haz doble clic en DetailPage.xaml en el Explorador de soluciones para abrirlo.
  2. En el código XAML del estado visual Snapped, agregamos una animación para cambiar el valor de la propiedad Margin en contentViewBorder.
    
    
            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentViewBorder" Storyboard.TargetProperty="Margin">
                <DiscreteObjectKeyFrame KeyTime="0" Value="20,5,20,20"/>
            </ObjectAnimationUsingKeyFrames>
    >
    
    

Este es el código XAML completo para el estado acoplado.



                <!-- The back button and title have different styles when snapped -->
                <VisualState x:Name="Snapped">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
                        </ObjectAnimationUsingKeyFrames>

                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="contentViewBorder" Storyboard.TargetProperty="Margin">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="20,5,20,20"/>
                        </ObjectAnimationUsingKeyFrames>

                    </Storyboard>
                </VisualState>

Presiona F5 para compilar y ejecutar la aplicación. Pruébala en distintas vistas y orientaciones.

Administración del ciclo de vida y el estado de la aplicación

Nota  En esta sección aplicas los conceptos descritos en Parte 2: Administrar el ciclo de vida y el estado de la aplicación. Para obtener más información sobre cómo guardar el estado de la aplicación, consulta la Parte 2.

Para conservar los recursos del sistema, el sistema suspende (y a veces finaliza) de forma automática las aplicaciones de la Tienda Windows que se ejecutan en segundo plano. Si la aplicación está bien diseñada, el sistema puede suspenderla, finalizarla y volver a iniciarla como si hubiera estado funcionando todo el tiempo. Aquí, agregas código para controlar la suspensión y reanudación de la aplicación. Afortunadamente, la mayor parte de la infraestructura la proporcionan las clases LayoutAwarePage y SuspensionManager en las plantillas de Visual Studio, así que solo necesitas agregar algo de código para guardar y restaurar la configuración.

Administración del estado de navegación

Para usar la clase SuspensionManager para administrar el estado de la aplicación, registras el elemento Frame raíz que tiene tu contenido con SuspensionManager. Cuando se suspende la aplicación, llamas a SuspensionManager.SaveAsync para guardar el estado de navegación de tu aplicación, que incluye la página actual y el parámetro de navegación que se pasó a esa página. Cuando se restaura la aplicación, se restaura el estado de navegación y el parámetro de navegación se pasa de nuevo a la página.

BR211380.wedge(es-es,WIN.10).gifPara guardar el estado de navegación

  1. Haz doble clic en App.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  2. Agrega la palabra clave async al método OnSuspending.
    
    private async void OnSuspending(object sender, SuspendingEventArgs e)
    
    
  3. Agrega este código al método OnSuspending, después del comentario "TODO".

    SuspensionManager.SaveAsync guarda el estado de navegación de Frame y ofrece a Page la oportunidad de guardar su contenido.

    
                //TODO: Save application state and stop any background activity
                await WindowsBlogReader.Common.SuspensionManager.SaveAsync();
    
    

Cuando se restaura la aplicación después de haberse suspendido y finalizado, se ejecuta este código para restaurar el estado de navegación de la aplicación.

BR211380.wedge(es-es,WIN.10).gifPara cargar el estado de navegación

  1. En App.xaml.cs/vb, agrega este código en el método OnLaunched inmediatamente después de la creación de instancias del nuevo Frame.

    Aquí, registras el Frame con la clase SuspensionManager.

    
                    // Add this code after "rootFrame = new Frame();"
                    WindowsBlogReader.Common.SuspensionManager.RegisterFrame(rootFrame, "AppFrame");
    
    
  2. Agrega este código en el método OnLaunched después del comentario "TODO".

    SuspensionManager.RestoreAsync restaura el estado de navegación del Frame y ofrece a Page la oportunidad de restaurar su contenido.

    
                        //TODO: Load state from previously suspended application
                        await WindowsBlogReader.Common.SuspensionManager.RestoreAsync();
    
    

Administración del estado de página

También necesitas guardar la configuración específica de la página cuando se suspende o restaura la aplicación. En la aplicación de lector de blogs, simplemente necesitas guardar y restaurar el elemento seleccionado en la página dividida. Esto lo haces en los reemplazos de los métodos SaveState y LoadState que proporciona la clase LayoutAwarePage.

BR211380.wedge(es-es,WIN.10).gifPara guardar el estado de página

  1. Haz doble clic en SplitPage.xaml.cs/vb en el Explorador de soluciones para abrirlo.
  2. Agrega este código en el método SaveState después del comentario "TODO".

    La clase SuspensionManager serializa y guarda el diccionario pageState en un archivo XML. Los datos guardados en pageState solo se guardan para esta sesión. Aquí, guardas el título de la entrada de blog seleccionada en la lista.

    
                    // TODO: Derive a serializable navigation parameter and assign it to
                    //       pageState["SelectedItem"]
                    if (selectedItem != null)
                    {
                        string itemTitle = ((FeedItem)selectedItem).Title;
                        pageState["SelectedItem"] = itemTitle;
                    }
    
    
    

BR211380.wedge(es-es,WIN.10).gifPara cargar el estado de página

  • En SplitPage.xaml.cs/vb, agrega este código en el método LoadState después del tercer comentario "TODO".
    
                        // TODO: Invoke this.itemsViewSource.View.MoveCurrentTo() with the selected
                        //       item as specified by the value of pageState["SelectedItem"]
    
                        string itemTitle = (string)pageState["SelectedItem"];
                        FeedItem selectedItem = FeedDataSource.GetItem(itemTitle);
                        this.itemsViewSource.View.MoveCurrentTo(selectedItem);
    
    

Incorporación de una pantalla de presentación y un logotipo

La primera impresión que recibe un usuario de tu aplicación es el logotipo y la pantalla de presentación. El logotipo aparece en la Tienda Windows y en la página de presentación. La pantalla de presentación se muestra inmediatamente cuando un usuario inicia la aplicación, y le envía comentarios de inmediato al usuario mientras la aplicación inicializa sus recursos. Se descarta cuando la primera página de tu aplicación está lista para mostrarse.

La pantalla de presentación consta de un color de fondo y una imagen de 620 x 300 píxeles. Estableces estos valores en el archivo Package.appxmanifest. Puedes hacer doble clic en este archivo para abrirlo en el editor de manifiestos. En la pestaña IU de la aplicación del editor de manifiestos, estableces la ruta de acceso a la imagen de tu pantalla de presentación y al color de fondo. La plantilla del proyecto proporciona una imagen en blanco predeterminada denominada SplashScreen.png. La reemplazas con tu propia imagen de pantalla de presentación que identifica claramente tu aplicación e invita a los usuarios a utilizar la aplicación inmediatamente. También puedes especificar un logotipo remplazando los archivos de logotipo de la plantilla con tu propio logotipo. Esta es la pantalla de presentación del lector de blogs.

Imagen de la pantalla de presentación.

La pantalla de presentación básica funciona bien para el lector de blogs, pero también puedes extenderla con las propiedades y métodos de la clase SplashScreen. Puedes usar la clase SplashScreen para obtener las coordenadas de la pantalla de presentación y usarlas para ubicar la primera página de la aplicación. Además, puedes saber cuándo se descarta la pantalla de presentación para determinar el momento de iniciar las animaciones de entrada de contenido.

Consultar el código

¿Te has quedado atascado o quieres revisar tu trabajo? Si así fuere, consulta Código completo del lector de blogs.

A continuación

Has aprendido a usar las plantillas de página integradas de Visual Studio Express 2012 para Windows 8 para crear una aplicación completa de varias páginas, así como a navegar por dichas páginas y transferir datos entre ellas. Has aprendido a usar los estilos y las plantillas para hacer que nuestra aplicación se ajuste a la personalidad del sitio web de The Windows Blog. También has aprendido a utilizar animaciones de tema, una barra de la aplicación y una pantalla de presentación para hacer que la aplicación se ajuste a la personalidad de Windows 8. Por último, has aprendido a adaptar tus aplicaciones a diferentes diseños y orientaciones para que se vea siempre de la mejor manera.

Para obtener más información sobre el desarrollo de aplicaciones, consulta la lista de recursos de aprendizaje y referencia para crear aplicaciones de la Tienda Windows.

Guía básica para crear aplicaciones de Windows en tiempo de ejecución con C# o Visual Basic.

 

 

Mostrar:
© 2014 Microsoft