Archive

Archive for the ‘WP7’ Category

Crear una cuenta de publicación para Windows Phone Marketplace

December 3rd, 2012 No comments

Crear una aplicación para Windows Phone puede ser una experiencia genial. Pero publicarla para que todos los usuarios de Windows Phone puedan acceder a ella es la mitad complementaria que definitivamente te hará sentir mucho mejor pues habrá muchas mas personas disfrutando de tu trabajo.

Para poder publicar aplicaciones en la tienda de Windows Phone (anteriormente llamada Windows Phone Marketplace), debes contar con una cuenta de desarrollador Windows Phone. Te anticipo que el costo es de $ 99 USD (lo dejo de manera genérica para que puedas hacer la conversión adecuada a tu moneda). Así que mientras estas leyendo esto te recomiendo que vayas sacando una poderosa tarjeta de crédito para terminar el proceso por completo.

Para comenzar deber unirte al centro de desarrolladores de Windows Phone, puedes hacerlo desde aquí. Antes de continuar te recuerdo que ya debes contar con una cuenta Windows Live ID, así que si no la tienes deberás hacerlo pues de lo contrario no podrás continuar con el proceso.

image

Al presionar el botón Join Now, verás una pantalla similar a la siguiente.

image

 

La opción de Country/region of residence or business  deberá tener marcado el nombre del país en el que radicas.

image

Para el tipo de cuenta existen dos posiblidades:

Company: Esta opción es para cuando tu cuenta venderá aplicaciones como un negocio de manera formal o a organizaciones gubernamentales.

Individual or student: Esta opción es para cuando quieres vender aplicaciones con solo tu nombre, simplemente si quieres conocer el mercado de manera individual o cuentas con una cuenta con DreamSpark

Después de haber habilitado el tipo de cuenta que utilizarás, solo debes aceptar los términos legales para poder continuar.

image

Al momento de continuar, en caso de que no te lo hayan pedido antes o no tengas tu sesión abierta. El sitio te pedirá ingresar con tu cuenta de Windows Live.

En la página de registro deberás ingresar toda la información solicitada o al menos la que tenga un asterisco ( * ) al finalizar cada campo pues se trata de información obligatoria. La primera sección son datos de la cuenta.

image

En la segunda opción, la de Publisher info, escribe el nombre con el que deseas aparecer al momento de publicar tus aplicaciones. Cuando lo hayas definido, solo debes confirmar que esté disponible.

image

 

Para darte una mejor referencia de lo importante que es considerar un nombre de publicador, puedes darte una vuelta por la tienda de aplicaciones de Windows Phone y verás que en cualquier aplicación que veas se mostrará el nombre que elegiste.

image

La mas grande diferencia entre los dos tipos de cuentas radica en el siguiente apartado. En el caso de la cuenta de tipo Company necesitarás indicar la información de quien quede a cargo de esta cuenta. Esto es sencillamente para evitar que se pueda publicar una aplicación sin la aprobación directa del responsable de publicación y en esto hago una mención importante, el administrador de la cuenta no debe ser exactamente el mismo que la administre.

image

 

En la siguiente pantalla podrás ingresar los datos de algún código promocional, de lo contrario solo presiona Next, aquí es donde verás el cobro real de tu licencia en moneda local.

image

En el último paso a seguir hay dos grandes opciones para poder pagar la cuenta de desarrollo de Windows Phone. Por medio de una tarjeta de crédito o PayPal. En cualquiera de los dos casos se te solicitará información relativa al método de pago.

image

 

Después de este paso y si todo salió en orden, ya deberás ver solo una pantalla de agradecimiento por haber terminado satisfactoriamente tu proceso de activación. La cuenta tomará cerca de 24 horas en activarse de manera completa y solo bastará que entres a la página inicial y simplemente ingreses con la cuenta que configuraste todo.

image

Después de haber ingresado, simplemente bastará que des clic sobre tu correo y podrás ver una imagen como la siguiente.

image

¡Ahí tienes! Ahora ya es momento de que puedas compartir con todos los usuarios Windows Phone esas geniales aplicaciones que has hecho.

Categories: WP7, WP71 Tags: , ,

Jugando con el ApplicationBar en los elementos de una App Panorama

May 2nd, 2012 No comments

Publicado por LucioMSP en abril 28, 2012

Hola amigos, el día de hoy les quiero compartir un pequeño tutorial sobre como manipular el ApplicationBar en todos los ítems que agreguemos en una aplicación estilo Panorama, es decir, hacer que se muestre el ApplicationBar solo en ciertos elementos de la Aplicación en Panorama y es que me encontré con varios problemas cuando quise realizar esto, ya que no encontré ningún material que me explicara al 100% lo que quería, además de que varias personas me comentaban que no se podía, o que no sabían, es por eso que quiero darlo a conocer. Parte 1
Categories: WP7 Tags:

Día 31: Promoviendo tu aplicación

December 31st, 2011 No comments

Esta es una traducción de Day 31: Promoting Your App, puedes encontrar el artículo aquí en su versión original en inglés.

dia31

Hacer que los usuarios encuentren tu aplicación puede parecer como algo que está fuera de tus manos, pero estás equivocado. Hay muchas cosas que puedes hacer para manejar la atención hacia tu aplicación. Esta sección se enfoca en algunas de las mejores prácticas que deberías utilizar para cada aplicación que crees.

La primera semana es vital

A menos de que tu aplicación se convierta en una gran sensación, es altamente posible que la primer semana de tu aplicación en el marketplace será en donde veas el más alto número de descargas diarias. Obtener exposición en la categoría “Nuevo” es una oportunidad muy buena y necesitas asegurarte de que estás manejando esto en una forma que hará a tu aplicación brillar por mucho mas que solo unos días. Al final, tu meta es catapultarla desde la categoría Nuevo a la categoría Top Apps. Los cuatro o cinco días que tienes que esperar para que tu aplicación sea aprobada podrían ser aprovechados para ejecutar una estrategia para hacer pública la expectativa de tu aplicación.

Enlazar a tu aplicación

Cuando ingresas tu aplicación por primera vez en el Marketplace, incluso antes de que la aplicación sea aprobada, tienes ya asignado un “deep link” que puedes usar para dirigir a las personas hacia tu aplicación usando una dirección web ordinaria. Aquí está el ejemplo del enlace a una de mis aplicaciones, MathMaster:

http://www.windowsphone.com/es-MX/apps/f08521cd-1cff-df11-9264-00237de2db9e

Este enlace te lleva a una página que intentará abrir Zune en la máquina del usuario, y después redireccionarlo a la página de tu aplicación en el Marketplace. Este enlace no funcionará a menos que tu aplicación haya sido aprobada. Recomendamos usar este link cada vez que puedas, especialmente en el sitio personalizado que creaste para tus aplicaciones. Estás planeando hacer eso ¿No es así?

Crear un portal web para tus aplicaciones

Una cosa importante que deberías haber aprendido al pasear por el Marketplace en el Día 27 de la serie original de Windows Phone fue que tu habilidad para discutir acerca de tus aplicaciones en el Marketplace es muy limitada. Unos cuantos pantallazos y aproximadamente 2,000 caracteres es todo lo que tienes. Al crear un sitio web para tus aplicaciones, creas muchas nuevas oportunidades para ti mismo.

1. Puedes crear conexiones reales con tus usuarios. El Marketplace de Windows Phone no te da ninguna indicación de quienes son tus usuarios. Un sitio web te permite interactuar con tus fans.

2. Puedes dar un monto de información muy enriquecido acerca de tu aplicación, incluyendo videos y otro contenido promocional que pueda hacer a tu aplicación mas atractiva.

3. Puedes relacionar a tus aplicaciones. El Marketplace no siempre hace un gran trabajo al promocionar tus otras aplicaciones a clientes potenciales, así que has que tu sitio web permita que eso suceda.

4. Tu aplicación ahora es detectable por gente que ni siquiera esta buscando activamente en el Marketplace.

5. Este sitio web no tiene que ser exactamente un sitio web por completo. No hay nada malo con crear una página en Facebook o cualquier otra red social que puedas personalizar. La idea final de este proceso es proveer un destino para tus fans, así ellos pueden pasar la voz acerca de tu genial aplicación.

Si quieres ver una plantilla genial para crear una página personalizada para tu aplicación, checa esta plantilla de Windows Phone en CodePlex. Es una página personalizable que se ve genial, usa pantallazos de tu aplicación, permite a tus usuarios dar comentarios y les da muchas formas de aprender mucho mas de tu aplicación. Aquí hay un pantallazo de la plantilla.

image28

Crear un video de guía para tu aplicación

Uno de los elementos importantes de tu sitio web debe ser incluir un video guía de tu aplicación. Las capturas de pantalla en el Marketplace son buenas, pero permitirle al usuario ver la experiencia total en una forma controlada nos dará siempre mucha mas información. Nuestra recomendación es utilizar un programa de captura de pantallas como TechSmith’s Camtasia. Camtasia hace muy fácil no solo capturar video desde el emulador, sino editar los resultados, agregar música de fondo y colocar información de introducción antes y después del video. Hay probablemente bastantes herramientas que harán esto por ti, pero en nuestra experiencia, Camtasia es la herramienta perfecta para el trabajo. Puedes ver un ejemplo de mi aplicación de MathMaster en YouTube aquí.

Puedes ver el video aquí.

Diviértete haciéndolo. En tu video puedes agregar un mayor nivel de interés a tu aplicación que las capturas de pantalla nunca podrán. Ahora que nos hemos enfocado en sitios web y videos, vamos a discutir cosas que puedes hacer dentro de tu aplicación para ayudar a promoverla.

Generar opiniones de tu aplicación

Las opiniones pueden ser un factor decisivo entre si tu aplicación tiene o no las descargas que estás buscando. Desafortunadamente, no hay un mecanismo para recordarle a los usuarios que comenten tu aplicación. Necesitas hacer esto por ti mismo. Recomendamos hacerlo como una adición agradable en tu aplicación en lugar de hacerlo una molestia para tu usuario.

Una idea que recomendamos es hacer un logro dentro de tu aplicación. Un poco de diversión sorprenderá y enganchará al usuario. Dale puntos por leer los créditos de la aplicación. Dale mas por usarla mas de 10 veces. Agregar logros a cualquier aplicación, encontrarás que tus usuarios estarán regresando mas y mas a ella. Quizá también desbloquees una pieza específica de funcionalidad que de otra manera no estaría disponible cuando opinen en tu aplicación.

Una segunda idea es contar el número de veces que tu usuario ha lanzado tu aplicación y pídele en la segunda, quinta y décima ocasión que opine tu aplicación. Pídelo gentilmente. No querrás molestarlo, pero si quieres su opinión. Puedes incluso usar la MarketplaceReviewTask para llevarlos directamente a la página de opiniones de tu aplicación.

Grandes opiniones generan mas tráfico. Comúnmente, una opinión de una estrella puede ser tan valiosa como una escrita. El promedio de evaluación (1-5) es desplegada donde quiera que este tu aplicación, así un alto rango comúnmente genera mas tráfico. Hacer que tus usuarios dejen una opinión tendrá un efecto positivo en los rangos de descarga de tu aplicación.

Cruzar tus aplicaciones entre ellas

Dentro de tu aplicación, puedes dar un lugar donde el usuario puede encontrar información acerca de tu compañía, contactos de soporte y otra información como el número de la versión. En este lugar, o ciertamente en una ubicación mas prominente, tienes una oportunidad para promover las otras aplicaciones que has creado. Usa tus íconos.  Usa los deep links o el lanzador MarketplaceDetailTask. Da una forma sencilla para tu usuario para encontrar y descargar las ofertas que tienes de tus otras aplicaciones.

Si realmente te quieres poner imaginativo, crea un archivo XML en tu servidor web que contenga toda la información acerca de tus aplicaciones y consúmelo en tus aplicaciones para crear la lista de todas tus aplicaciones. De esta forma, cuando agregues una nueva aplicación a tu catálogo, no tendrás que actualizar todas tus aplicaciones, solo hacer esta promoción “cruzada”.

En resumen

Hay muchísimas cosas que necesitas hacer para tener a tu aplicación lista, después de que has terminado tu aplicación. Asegúrate que has considerado tu estrategia de promoción antes de presionar el botón final de “Ingresar” en tu aplicación. Crear una comunidad alrededor de tu aplicación solo ayudará a hacer crecer a tu audiencia, porque los usuarios entusiastas son también evangelistas poderosos de tu esfuerzo.

Si te has tomado este tiempo para crear una nueva aplicación sorprendente para Windows Phone, necesitas estar seguro de que va a tener el impacto potencial que estas esperando. Enfocarte en monetizar, promocionar y opinar es tan importante como tu aplicación misma.

Este es el artículo final de esta serie. Espero que la hayas disfrutado tanto como nosotros lo hemos hecho al escribirla. Muchas gracias por leer todos los post.

Categories: Tutoriales, WP7 Tags:

Día 30: Base de datos local

December 31st, 2011 1 comment

Esta es una traducción de Day 30: Local Database, puedes encontrar el artículo aquí en su versión original en inglés.

dia30

¿Qué es una base de datos local?

En la versión original de Windows Phone 7, podíamos salvar información pero tomaba cierto código especial o utilizar bases de datos de terceros como SterlingDB para tener un repositorio de información relaciona que algunas aplicaciones necesitan. Esto limitó algunos tipos de aplicaciones que algunos desarrolladores pudieron producir para los usuarios.

En Windows Phone Mango, los desarrolladores aún cuentan con el almacenamiento aislado para mantener información e información almacenada para sus aplicaciones pero ahora tenemos SQL CE como un elemento de almacenamiento relacional para crear aplicaciones aún mejores para Windows Phone.

Como otras soluciones de bases de datos para el Windows Phone original, la base de datos nativa de SQL CE creada en Mango tiene su información almacenada en el almacenamiento aislado del dispositivo. Puedes aprender mas acerca del almacenamiento aislado aquí. Microsof tampoco creó nuevas formas de trabajar con la información en el teléfono y en su lugar implementó LINQ a SQL para todas las operaciones de las bases de datos. LINQ a SQL es usado para hacer todas la funciones para la aplicación cuando se trate de manejar la información incluyendo crear la información, llenar la base de datos, obtener información u finalmente guardar y borrarla.

Un buen tutorial de LINQ para SQL esta aquí en MSDN.

Ajustar una base de datos local para tu aplicación de mango

Como todos los puntos de inicio para Windows Phone 7, empezaremos creando un proyecto de Windows Phone Databound Application dentro de Visual Studio 2010.

clip_image002_thumb4

Pudimos haber comenzado con una aplicación sencilla de Windows Phone, pero me gustan los elementos adicionales que te dan para permitir que tu aplicación tenga mejores patrones de diseño como Model-View-ViewModel (MVVM).

A continuación actualizaremos el MainPage del proyecto para permitir que la información sea agregada a la sabes de datos. Nuestra información de ejemplo estará coleccionando ideas que todos tenemos y necesitamos  recordar. No iremos a gran detalle acerca del diseño del MainPage pero aquí está el XAML para obtener la apariencia para nuestro colector de ideas.

<phone:PhoneApplicationPage
x:Class=”Dia_30_BaseDatosLocal.MainPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:shell=”clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone”
xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″
xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″
mc:Ignorable=”d” d:DesignWidth=”480″ d:DesignHeight=”768″
d:DataContext=”{d:DesignData SampleData/MainViewModelSampleData.xaml}”
FontFamily=”{StaticResource PhoneFontFamilyNormal}”
FontSize=”{StaticResource PhoneFontSizeNormal}”
Foreground=”{StaticResource PhoneForegroundBrush}”
SupportedOrientations=”Portrait”  Orientation=”Portrait”
shell:SystemTray.IsVisible=”True”>

<Grid x:Name=”LayoutRoot” Background=”Transparent”>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>

<StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,17,0,28″>
<TextBlock x:Name=”ApplicationTitle” Text=”LA LIGA SILVERLIGHT” Style=”{StaticResource PhoneTextNormalStyle}”/>
<TextBlock x:Name=”PageTitle” Text=”base datos” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>
</StackPanel>

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto” />
<RowDefinition Height=”Auto” />
</Grid.RowDefinitions>

<ListBox x:Name=”lstIdeas” ItemsSource=”{Binding IdeaItems}”
Grid.Row=”0″ Margin=”12, 0, 12, 0″ Width=”440″>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment=”Stretch” Width=”440″>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”50″ />
<ColumnDefinition Width=”*” />
<ColumnDefinition Width=”100″ />
</Grid.ColumnDefinitions>
<CheckBox IsChecked=”{Binding IsComplete, Mode=TwoWay}” Grid.Column=”0″ VerticalAlignment=”Center”/>
<TextBlock Text=”{Binding ItemName}” FontSize=”{StaticResource PhoneFontSizeLarge}” Grid.Column=”1″ VerticalAlignment=”Center”/>
<Button Grid.Column=”2″ x:Name=”btnBorrarIdea” BorderThickness=”0″ Margin=”0″ Click=”btnBorrar_Click”>
<Image Source=”appbar.delete.rest.png”/>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<Grid Grid.Row=”1″>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”*” />
<ColumnDefinition Width=”Auto” />
</Grid.ColumnDefinitions>
<TextBox x:Name=”txtNuevaIdea” Grid.Column=”0″ Text=”agregar nueva idea”
FontFamily=”{StaticResource PhoneFontFamilyLight}” GotFocus=”txtNuevaIdea_GotFocus”/>
<Button Content=”+” Grid.Column=”1″ x:Name=”btnAgregar” Click=”btnAgregar_Click” FontSize=”29.333″/>
</Grid>
</Grid>
</Grid>

</phone:PhoneApplicationPage>

También para dejar que nuestra aplicación se compile y corra sin hacer nada el código de abajo será agregado en el archivo MainPage.xaml.cs dentro de la clase MainPage y después del constructor.

private void txtNuevaIdea_GotFocus(object sender, RoutedEventArgs e)
{
txtNuevaIdea.Text = String.Empty;
}

private void btnAgregar_Click(object sender, RoutedEventArgs e)
{

}

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
}

Trabajar con el Data Context

El Data Context es el punto que nos permite trabajar con la base de datos y también con las clases proxy que representan las tablas de nuestra base de datos. El Data Context es también una clase y trabaja contra un número de  clases de tipo“Objeto CLR viejo y plano” (POCO) que fueron creadas para este proyecto. Los objetos de tipo tabla que representan las tablas de nuestra base de datos contendrán una colección de entidades para cada registro de la tabla almacenado en la base de datos, Otros detalles acerca de nuestra base de datos están también dados por medio del Data Context tales como llaves primarias y mapas de asociación entre tablas.

Solo un recordatorio de que esta base de datos no tiene conexión con el SQL Server 2008 R2 que esta corriendo localmente en tu PC o un servidor en tu proveedor de hosting o compañia y solo mantiene la información en tu dispositivo.

No hay mucho de la clase de tipo DataContext ademas de la cadena de conexión con la que estamos familiarizados en desarrollo y propiedades de cada tabla que existen en nuestra base de datos. Piensa en el DataContext como el “eje” para la información de tu aplicación. El código para el Data Context de nuestra aplicación de ejemplo es el siguiente:

public class IdeaDataContext : DataContext
{
public static string cadenaConexion = “Data Source=isostore:/Ideas.sdf”;
public IdeaDataContext(string cadenaConex): base(cadenaConex)
{ }

public Table<IdeaItem> ElementoIdea;
}

Nota que el tipo ElementoIdea estará detallado en la siguiente sección que cubre la creación de la base de datos.

Crear la base de datos

A diferencia de las aplicaciones que corren desde tu PC o en IIS 7, las bases de datos de Windows Phone deben ser creadas e inicializadas en la primera instancia de tu aplicación. Primero veremos como crear las clases que representarán las tablas de nuestra base de datos y después mirar la inicialización de la base de datos,

Por cada tabla que necesitamos que sea creada y expuesta a través de nuestra base de datos en nuestro teléfono para la aplicación, necesitamos crear un nuevo POCO. Dado que etas clases representan las entidades que estarán almacenadas en la base de datos, vamos a llamarlas clases de entidad. Para iniciar la clase de entidad debemos adherir dos interfaces.

* INotifyPropertyChanged – La interfaz INotifyPropertyChanged es usada para notificar a los clientes, típicamente enlazando que una propiedad ha cambiado.

* InotifyPropertyChanged – La interfaz INotifyPropertyChanging es usada para notificar a los clientes, típicamente enlazando que una propiedad esta cambiando.

Estas dos interfaces permitirán a cada entidad notificar al Data Context que esta en proceso de cambiar o esta cambiando. Esto después será reflejado en las vistas XAML de nuestra aplicación por medio del enlazado que hemos hecho.

Esta clase de entidad debe ser anotada como una tabla para permitir al DataContext saber como trabajar con ella. Una clase de entidad debe tener también propiedades públicas y privadas para cada propiedad de la Entidad también como tener la propiedad privada anotada para dar metadatos valiosos acera de la propiedad de la entidad (a.k.a. la columna de la base de datos). Recuerda tener las propiedades de la llave primaria para cada una de tus clases de entidad.

Debajo esta la clase de entidad ElementoIdea que estará localizada en la tabla ElementoIdea referenciada en el DataContext que creamos antes.

[Table]
public class IdeaItem : INotifyPropertyChanged, INotifyPropertyChanging
{
private int idElementoIdea;
private string nombreElemento;
private bool estaAcompletada;

public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangingEventHandler PropertyChanging;

[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int IdElementoIdea
{
get
{
return idElementoIdea;
}
set
{
if (idElementoIdea != value)
{
NotifyPropertyChanging(“IdElementoIdea”);
idElementoIdea = value;
NotifyPropertyChanged(“IdElementoIdea”);
}
}
}

[Column]
public string NombreElemento
{
get
{
return nombreElemento;
}
set
{
if (nombreElemento != value)
{
NotifyPropertyChanging(“NombreElemento”);
nombreElemento = value;
NotifyPropertyChanged(“NombreElemento”);
}
}
}

[Column]
public bool EstaAcompletada
{
get
{
return estaAcompletada;
}
set
{
if (estaAcompletada != value)
{
NotifyPropertyChanging(“EstaAcompletada”);
estaAcompletada = value;
NotifyPropertyChanged(“EstaAcompletada”);
}
}
}

[Column(IsVersion = true)]
private Binary version;

private void NotifyPropertyChanged(string nombrePropiedad)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(nombrePropiedad));
}
}

private void NotifyPropertyChanging(string nombrePropiedad)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(nombrePropiedad));
}
}
}

Finalmente debemos crear la base de datos si esta no existe. Esto lo haremos en el constructor de la aplicación. Encontrarás esto en el archivo App.xaml.cs. El código que será agregado al final del método constructor es como el que sigue.

using (IdeaDataContext baseDatos = new IdeaDataContext(IdeaDataContext.cadenaConexion))
{
if (baseDatos.DatabaseExists() == false)
{
baseDatos.CreateDatabase();
}
}

Ahora tenemos una base de datos que ha sido creada e inicializada en el almacenamiento aislado. Una cosa mas para recordar es que las bases de datos locales en Windows Phone 7 no pueden ser directamente compartidas entre aplicaciones en el teléfono dada la seguridad otorgada por el “sandbox” en el sistema operativo Windows Phone.

Soporte de LINQ to SQL para Windows Phone Mango

El SDK de Windows Phone 7.1 permite algunos, no todos los elementos de LINQ to SQL dentro de Windows Phone. Los siguientes son solo algunos elementos para recordar al trabajar con información y LINQ to SQL en Windows Phone Mango.

* Execute Command no es soportado.

* Los objetos ADO.NET (tales como DataReader) no están soportados.

* Solo son soportados los tipos de datos de Microsoft SQL Server Compact Edition (SQL CE)

Para obtener mas limitantes y elementos de usar LINQ to SQL en Mango, por favor lee la página de MSDN aquí.

Obtener Información desde una base de datos local

Para obtener información o cualquier trabajo relacionado con la base de datos local, primero debemos crear el DataContext y conectarlo a la base de datos. Esto sucederá en el MainPage por medio de una variable privada para el DataContext, una propiedad de tipo Observable Collection para las ideas en la base de datos y en el constructor del MainPage como se muestra aquí.

private IdeaDataContext ideaDB;

private ObservableCollection<IdeaItem> listaIdeas;
public ObservableCollection<IdeaItem> ListaIdeas
{
get
{
return listaIdeas;
}
set
{
if (listaIdeas != value)
{
listaIdeas = value;
NotifyPropertyChanged(“IdeaItems”);
}
}
}

public MainPage()
{
InitializeComponent();
ideaDB = new IdeaDataContext(IdeaDataContext.cadenaConexion);

this.DataContext = this;
}

Para obtener nuestras ideas localizadas en la base de datos local usaremos LINQ to SQL para consultar y obtener la colección de la base de datos vía el DataContext.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
var ideaEnBaseDatos = from IdeaItem idea in ideaDB.ElementoIdea
select idea;

ListaIdeas = new ObservableCollection<IdeaItem>(ideaEnBaseDatos);
base.OnNavigatedTo(e);
}

Las ideas ahora están enlazadas y reflejadas en el MainPage.xaml .

clip_image0033

Almacenar información a la base de datos local

Finalmente crearemos la forma de guardar nuestra información de ideas a la base de datos local. No enviaremos las ideas a la base de datos a menos de que necesitemos incrementar el rendimiento. Mantendremos todas las ideas en la colección local que creamos como una propiedad del MainPage (ListaIdeas). La adición de nuevas ideas a la base de datos local se efectuará cuando el botón de agregar idea cuando esta sea agregadas a la colección ListaIdeas.

private void btnAgregar_Click(object sender, RoutedEventArgs e)
{
IdeaItem nuevaIdea = new IdeaItem { NombreElemento = txtNuevaIdea.Text };
ListaIdeas.Add(nuevaIdea);
ideaDB.ElementoIdea.InsertOnSubmit(nuevaIdea);
}

Como lo mencioné antes, las ideas coleccionadas desde el usuario no estarán almacenadas en la base de datos hasta que la aplicación se haya salido del MainPage ya sea que salga de la aplicación o que la aplicación se mueva a una nueva página. El código para el evento es el siguiente.

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
ideaDB.SubmitChanges();
}

En resumen

¡Eso es todo! Ahora tienes una forma simple de crear, almacenar y obtener información relacional en tus aplicaciones Windows Phone. ¿Cómo la piensas usar?

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana el último artículo de la serie. cubriremos las mejores prácticas para promocionar tus aplicaciones de Windows Phone. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 29: Globalización

December 29th, 2011 1 comment

Esta es una traducción de Day 29: Globalization, puedes encontrar el artículo aquí en su versión original en inglés.

dia29

Globalización contra Localización

Las personas comúnmente se confunden cuando se discute acerca de globalización y localización. Ambas tratan de lidiar con presentar contenido de una manera amigable por todo el mundo, pero la distinción es que la globalización trabaja con el formato de los elementos, tales como el tiempo, fechas, tipos de moneda y números en la forma en la que el usuario este familiarizado considerando, mientras que la localización involucra desplegar el idioma nativo del usuario en la interfaz. Este artículo cubrirá el uso de ambas técnicas para crear aplicaciones que puedan alcanzar una gran audiencia con la interfaz de usuario mas amigable posible.

Estaremos creando una aplicación simple durante el curso de este artículo que soporte a ambas, globalización y localización. Esta aplicación rápidamente genera un mensaje de correo electrónico que permite saber al contacto que estas retrasado para una reunión.

Configurar soporte para la localización

Después de crear un nuevo Windows Phone con C#, necesitaremos hacer algunas cosas para configurar la aplicación para que soporte la localización.

Definir un lenguaje neutral para el ensamblado

Dado que estamos localizando nuestra aplicación, necesitamos decirle al proyecto cual es la localización preestablecida. Para hacer esto, vamos a  ir cuadro de diálogo de las propiedades del proyecto y clic en “Assembly Information” y después especificar el idioma neutral para nuestra aplicación – eso es, el lenguaje que será utilizado si no hay recursos locales definidos que coincidan con los del usuario. Para este ejemplo, ajustaremos el lenguaje neutral en “English (United States)”.

clip_image0024

Indicando la cultura soportada

A continuación necesitamos decirle al proyecto que lenguajes están soportados. Visual Studio no expone esta parte de información del proyecto, pero podemos editarla fácilmente. Asegúrate de guardar todos los cambios de modo que todos los cambios al .csproj estén guardados antes de editar el archivo. Después ve a la carpeta del proyecto en el disco  dando clic derecho en el proyecto y selecciona “Open Folder in Windows Explorer”. Selecciona el .csproj para tu aplicación (se cuidadoso de no seleccionar el archivo .csproj.user) y ábrelo con el bloc de notas o tu editor de textos favorito (N. del T. una amplia recomendación es Notepad++).

Busca el elemento <SupportedCultures></SupportedCultures> y agrega el código de las culturas que deseas soportar separando cada cultura por un punto y coma. Esta lista no deberá incluit el lenguaje neutral del ensamblado. Visita http://msdn.microsoft.com/en-us/library/hh202918(v=VS.92).aspx para una lista de culturas soportadas por varias versiones de Windows Phone. Para los propósitos de este ejemplo, estaremos soportando Español, Chino simplificado y Francés, además del el preestablecido que fue el Inglés, así que nuestro nodo de SupportedCultures se verá así.

<SupportedCultures>es-ES;zh-CN;fr-FR</SupportedCultures>

Después de hacer tus cambios, guarda el archivo .csproj y ve de regreso a Visual Studio. Presiona “recargar” cuando Visual Studio te diga que el proyecto ha cambiado para que estos cambios puedan tener efecto.

Crear un archivo de recursos base

Ahora que tenemos una cultura preestablecida y una lista de otras mas soportadas, podemos empezar a definir los recursos específicos para cada cultura. Empezaremos agregando un archivo para los recursos preestablecidos y movernos para agregar recursos para culturas específicas. Como una buena práctica de localización, cualquier cadena que el usuario vea deberá ser incluida en estos archivos en lugar de hacerlas de modo estático en XAML o en un archivo de código.

Necesitamos agregar un archivo de recursos al proyecto que defina las cadenas de lenguaje para la aplicación. Para hacer esto, daremos clic derecho en nuestro proyecto en el explorador de soluciones y elegimos “Add –> New Item”. Desde aquí, agregaremos un archivo de recursos. Puedes llamarlo como gustes, para este ejemplo lo llamaremos Cadenas.

clip_image004_thumb5

Agregar el archivo nos lleva al editor de recursos para este reecurso. El editor contiene una tabla con tres columnas, Name, Value y Comment. Nombre es el nombre auto generado por code-behind para el recurso y sirve como clave única para identificar un recurso. Value es el valor específico de la cultura para este recurso y es lo que usaremos para almacenar el texto que el usuario vea. Comment no es usado por la aplicación, pero es útil para señalar para que usamos tal recurso y donde lo usamos, además puede ayudar demasiado durante la traducción a otros lenguajes. También verás un modificador de acceso en la cima del editor de recursos. Este es interno de forma preestablecida pero necesitamos cambiarlo a público de modo que podamos enlazar estos valores mas adelante.

Aquí esta nuestro ejemplo después de agregar las cadenas apropiadas y cambiar el modificador de acceso a público:

clip_image006_thumb3

Crear archivos de recursos específicos para cada cultura

Ahora que tenemos nuestros recursos preestablecidos definidos, podemos iniciar a crear recursos personalizados para el proyecto. Empezaremos definiendo los recursos en español para esta aplicación. Presiona y arrastra el archivo cadenas.resx en el explorador de soluciones para crear una copia del archivo y después renómbralo como “CopiaDeCadenas.resx” a “Cadenas.es-ES.resx” (es-ES es el código de cultura para el español). Es importante que este nuevo archivo inicie con el mismo nombre como este nuevo archivo inicie con el mismo nombre que el previo  pero teniendo la localización adecuada al final de este o el archivo no podrá ser utilizado de manera adecuada para mapear la localización adecuada. Una vez que has renombrado tal archivo, abre el archivo Cadenas.es-ES.resx y modifica la columna Value para cada recurso. Una buena fuente para traducciones es Bing Translator, además de que debes verificar las traducciones con alguien que entienda el lenguaje antes de desplegar. Es importante que la columna Name coincida entre los archivos de recursos para que los recursos puedan ser mapeados apropiadamente.

Una vez  que has terminado con esto, sigue el mismo procedimiento para cualquier localidad adicional que desees soportar siendo cuidadoso de que todos los recursos tienen un modificador de acceso público, mantén el mismo nombre y contén el código de cultura apropiado. Es también importante notar que el editor de recursos puede no desplegar ciertos conjuntos de caracteres extranjeros correctamente cuando copies y pegues desde el traductor de Bing al editor de recursos, pero estos caracteres se verán bien en el dispositivo o emulador.

clip_image008_thumb3

Crear una interfaz de usuario no localizada

Ahora que tenemos un conjunto de cadenas localizadas, mejor comenzamos a crear la interfaz en donde podamos usarlas. Nuestra aplicación de ejemplo tendrá algunos campos, una barra de aplicación y un encabezado estándar. Dado que queremos incluir datos en este ejemplo para demostrar la globalización, haremos referencia al Toolkit de Silverlight para Windows Phone y usar el control de TimePicker contenido en ese ensamblado. Este artículo no irá hasta el detalle de descargar, instalar y hacer referencia al Toolkit, pero este está disponible y nos será útil.

clip_image0102

Nuestro MainPage no localizado se verá así.

<phone:phoneapplicationpage x:Class="Dia_29_Globalizacion.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
xmlns:Controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">

<grid x:Name="LayoutRoot" Background="Transparent">
</grid><grid .RowDefinitions>
<rowdefinition Height="Auto"/>
<rowdefinition Height="*"/>
</grid>

<stackpanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<textblock x:Name="ApplicationTitle" Text="{Binding Source={StaticResource Cadenas}, Path=Resources}"
Style="{StaticResource PhoneTextNormalStyle}" />
<textblock x:Name="PageTitle" Text="{Binding Resources.PageTitleSendMessage, Source={StaticResource Cadenas}}"
Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" TextWrapping="Wrap" />
</stackpanel>

<scrollviewer Margin="12,0,12,0" Grid.Row="1">
<stackpanel x:Name="ContentPanel">
<textblock TextWrapping="Wrap" Text="{Binding Resources.FieldTo, Source={StaticResource Cadenas}}" Style="{StaticResource PhoneTextSubtleStyle}" />
<textbox x:Name="txtPara" TextWrapping="Wrap" InputScope="EmailUserName" />
<hyperlinkbutton x:Name="btnElegirContacto" Content="{Binding Resources.LinkChooseContact, Source={StaticResource Cadenas}}"
HorizontalContentAlignment="Left" Foreground="{StaticResource PhoneAccentBrush}"
Click="btnElegirContacto_Click" Margin="{StaticResource PhoneVerticalMargin}" />
<textblock TextWrapping="Wrap" Text="{Binding Resources.FieldSubject, Source={StaticResource Cadenas}}"
Style="{StaticResource PhoneTextSubtleStyle}" />
<textbox x:Name="txtTitulo" TextWrapping="Wrap" Text="{Binding Resources.AppTitle, Source={StaticResource Cadenas}}"
InputScope="Text" />
<checkbox x:Name="chkInluirJustificacion" Content="{Binding Resources.CheckIncludeAReason, Source={StaticResource Cadenas}}" />
<textbox x:Name="txtRazon" TextWrapping="Wrap" Text="{Binding Resources.DefaultReason, Source={StaticResource Cadenas}}"
InputScope="Text" IsEnabled="{Binding IsChecked, ElementName=chkInluirJustificacion}" />
<checkbox x:Name="chkIncluirETA" Content="{Binding Resources.CheckShouldArriveBy, Source={StaticResource Cadenas}}" />
<controls:timepicker x:Name="timeLlegada"
ValueStringFormat="{}{0:t}"
IsEnabled="{Binding IsChecked, ElementName=chkIncluirETA}"
Margin="0,-12,0,0" />
<checkbox x:Name="chkIncluirDiagnostico"
Content="{Binding Resources.CheckIncludeDiagnostics, Source={StaticResource Cadenas}}" />
</stackpanel>
</scrollviewer>


</phone:phoneapplicationpage><phone:phoneapplicationpage .ApplicationBar>
<shell:applicationbar IsMenuEnabled="False">
<shell:applicationbariconbutton x:Name="btnEmail" IconUri="/Imagenes/email.png" IsEnabled="True" Text="send" Click="btnEmail_Click" />
</shell:applicationbar>
</phone:phoneapplicationpage>

Obviamente este XAML contiene un número de cadenas estáticas las cuales no queremos para una aplicación localizable. Necesitamos que la interfaz de usuario tome ventaja de las cadenas de recursos.

Obtener Cadenas de recursos en XAML

Afortunadamente el diseñador de recursos con el que hemos estado trabajando tiene clases automáticamente generadas para acceder a estos recursos. Desafortunadamente, no podemos enlazar fácilmente estos en XAML por la clase de cadenas auto generadas que tiene un constructor interno y propiedades estáticas así que necesitaremos crear un “envoltorio” de recursos que exponga estos en una forma que podamos enlazar.

Agrega una nueva clase al proyecto llamada ProveedorCadenas.cs e incluye el siguiente código.

Ahora ve hacia el archivo de App.xaml y agrega un nuevo recurso a la aplicación con el calificador adecuado de espacio de nombres. Este recurso estará disponible a través de la aplicación entera y te dará un fácil acceso a la localización de cadenas. Cuando termines, tu App.xaml se deberá ver así.

<Application
x:Class=”Dia_29_Globalizacion.App”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” xmlns:local=”clr-namespace:Dia_29_Globalizacion”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:shell=”clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone”>

<Application.Resources>
<local:ProveedorCadenas x:Key=”Cadenas” />
</Application.Resources>

<Application.ApplicationLifetimeObjects>
<shell:PhoneApplicationService
Launching=”Application_Launching” Closing=”Application_Closing”
Activated=”Application_Activated” Deactivated=”Application_Deactivated”/>
</Application.ApplicationLifetimeObjects>

</Application>

Ahora que hemos definido nuestro StringProvider como un recurso, podemos enlazarlo al MainPage. En este caso estamos enlazando a la sub propiedad de la propiedad de Reosurces representando el nombre del recurso como lo definimos antes en la colección de recursos y usando el objeto de  tipo ProveedorCadenas  como una fuente de enlazado. Por ejemplo, el título de nuestra aplicación se vuelve:

<TextBlock x:Name=”ApplicationTitle” Text=”{Binding Source={StaticResource Cadenas}, Path=Resources}” Style=”{StaticResource PhoneTextNormalStyle}” />

Ambos, tanto Blend como Visual Studio deberán reconocar este enlazado y desplegar la cadena de lenguaje neutral (el valor en Cadenas.resx) en el diseñador si el proyecto ha sido compilado desde que los recursos fueron agregados.

Cuando creas aplicaciones globalizadas, ten cuidado de que muchas cadenas de lenguajes serán mayores de lo que es en el idioma preestablecido. Dado esto, es importante que ajustes la propiedad TextWrapping=”Wrap”  donde sea aplicable y usa un diseño flexible de estructuras de diseño como ScrollViewers y StackPanels que puedan adaptarse a contenido multi líneas cuando sea necesario. Dado el potencialmente largo recurso de las cadenas, es recomendable ajustar la propiedad SupportedOrientations=”PortraitOrLandscape” en la página cuando sea apropiado.

Es también importante estar al pendiente de que no todas las localidades soportan diferentes fuentes. Tu mejor apuesta en el caso de localización de aplicaciones es evitar las fuentes manualmente especificada o personalización de fuentes y en su lugar confiar en las fuentes ya creadas. Visita http://msdn.microsoft.com/en-us/library/hh202920(v=VS.92).aspx para mas información.

Referirse a cadenas localizadas en C#

Este enfoque funcionará para la mayoría de las cadenas, pero las guías de diseño Metro requieren que el título de la aplicación en la cima de la página esté en mayúsculas y nuestra cadena en el archivo de recursos usa mayúsculas capitales. Podríamos definir un nuevo recurso solo para la etiqueta de título o escribir un convertidor de valores de tipo Uppercase para el enlazado, pero en su lugar solo vamos a ajustar el título en el code behind para poder demostrar el acceso a recursos localizados desde el código al agregar la siguiente línea en el constructor de tu MainPage:

Localizar la barra de aplicacón

Los elementos de la barra de aplicación actualmente no soportan el enlazado de datos dado que ellos no son realmente controles de Silverlight personalizables. En su lugar, tendremos que ajustar manualmente el texto de nuestro ApplicationBarIconButton en el code behind al referirnos a la propiedad auto generada para nuestro nombre de recurso en el recurso de Cadenas como se muestra.

Ahora tenemos una aplicación localizada. Probar la aplicación en el emulador usando los ajustes para el lenguaje en francés resultará en lo siguiente.

clip_image0122

Soportar globalización

Ahora que tenemos una aplicación localizable, vámonos a la globalización. Dado que la globalización se encarga de los ajustes culturales del usuario respectivo, es importante dar el correcto IFormatProvider a varios métodos de formato de cadenas cuando sea apropiado. Afortunadamente .NET nos da CultureInfo.CurrentCulture el cual representa los ajustes culturales del usuario actual y pueden ser usados para formatear las cadenas para la interfaz del usuario. Cuando se hagan comparaciones estándar o al lidiar con la serialización u otras operaciones que el usuario no ve, es importante usar CultureInfo.InvariantCulture para asegurar que tu aplicación funcione adecuadamente en todos los ajustes de cultura.

A diferencia de la localización, no tienes que hacer nada para soportar una cultura particular e el framework .NET se preocupará de la mayoría de operaciones de formato de cultura por tí. Es también una buena práctica dar el formato apropiado de cadenas y especificar  el CultureInfo,CurrentCulture como un IFormarProvider cuando sea apropiado.

Por ejemplo, el código de nuestra aplicación esta hecho para generar un correo electrónico que haga explícito uso de CurrentCulture y formato de cadenas.

Dado que la globalización esta separada de la localización, corre a aplicación en un lenguaje sin cadenas localizadas resultará en valores apropiadamente globalizados así como estos valores alemanes en la imagen de abajo:

clip_image0142

Especificar el formato de cadenas en XAML

Ocasionalmente querrás ser capaz de especificar un formato de cadena en XAML  ya sea como un parámetro para un value converter o como una propiedad en un control previamente creado. En nuestro ejemplo ajustaremos explícitamente el formato de la cadena de nuestro TimePicker para acortar el formato de tiempo para la cultura actual (“t”). Para hacer esto, prefijamos el formato de la cadena con un par de llaves como se muestra aquí.

<Controls:TimePicker x:Name=”timeLlegada”
ValueStringFormat=”{}{0:t}”
IsEnabled=”{Binding IsChecked, ElementName=chkIncluirETA}”
Margin=”0,-12,0,0″ />

Es también posible ajustar esto en C# de la siguiente manera.

O mucho mas preciso.

Probando diferentes culturas

Hasta ahora, hemos creado una aplicación enteramente funcional que soporte la globalización y localización. Quizá te preguntes ahora como probarla en diferentes culturas. Los dispositivos Windows Phone quizá no te permitan cambiar el idioma de despliegue de tu pantalla, pero afortunadamente, Microsoft le dio esta capacidad al emulador.

Para acceder a estos ajustes, ve al menú de aplicaciones del emulador en la pantalla de inicio y escoge la aplicación de ajustes. Desde ahí da clic en el elemento del pivot que dice Region+Lenguaje

clip_image0161

Esta pantalla te permite personalizar el lenguaje que se mostrará en el teléfono al ajustar en la lista de selección el lenguaje que quieres mostrar y después dando clic en el enlace de “Da tap aquí para aceptar los cambios”. Al hacerlo, se reiniciará la imagen del SO Windows Phone de tu emulador y aplicará los ajustes de lenguaje y globalización que has elegido. Puede ser confuso usar páginas de ajustes en un lenguaje que no conoces para cambiar los ajustes regionales, así que es una gran idea estudiar el diseño de la pantalla antes de aplicar nuestros cambios. Una vez que el emulador se haya reiniciado al lanzar nuestra aplicación en el emulador podrás verificar que la aplicación respeta el lenguaje del usuario y sus ajustes culturales.

Consideraciones de publicación

Cuando quieras desplegar una aplicación que soporte diferentes lenguajes y culturas, asegúrate de elegir la distribución que coincida con los lenguajes soportados ya sea seleccionando una distribución global al publicar tu aplicación y ajustando los precios o seleccionando lugares individuales que desees soportar.

En Resumen

Ahora sabes como crear una aplicación desde el inicio hasta el final que ofrecerá la mejor experiencia al dar una aplicación propiamente globalizada y localizada para la audiencia global que usa Windows Phone.

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana, vamos a regresar a la información, y vamos a cubrir como usar una base de datos local en tu aplicación. Nos vemos

Categories: Tutoriales, WP7 Tags:

Día 28: Biblioteca multimedia

December 28th, 2011 No comments

Esta es una traducción de Day 28: Media Library, puedes encontrar el artículo aquí en su versión original en inglés.

dia28

Hoy vamos a echar un vistazo a la clase MediaLibrary que es parte del espacio de nombres Microsoft.Xna.Framework.Media. Como el nombre sugiere, esta clase nos da acceso a la biblioteca de medios del usuario. Una biblioteca de medios en Windows Phone almacena imágenes y música. Al usar las biblioteca de medios, puedes integrar este contenido en tus propias aplicaciones. Hay muchas razones por las que un desarrollador querría hacer esto. Aquí hay algunas ideas:

* Para mostrar al usuario una lista de canciones y dejarlos seleccionar la música de fondo mientras usa tu aplicación.

*Permitir al usuario descargar sus imágenes desde un servicio. (por ejemplo Flickr) y agregarlas a la biblioteca.

* Usar música de un artista o género desde la biblioteca de medios para hacer sugerencias de otros contenidos similares en los que el usuario podría interesarse.

Para mostrar como usar la biblioteca de medios, he creado una aplicación de ejemplo. Esta aplicación enlistará todas las canciones que se encuentren en la biblioteca multimedia del usuario, reproducir una canción cuando el usuario la seleccione y permitirle seleccionar una imagen de la biblioteca para usarla como fondo de pantalla. La aplicación usa la biblioteca multimedia para obtener una lista de las canciones y también guarda una imagen a la biblioteca para el usuario.

clip_image0027

Guardar la imagen a la biblioteca multimedia

En la aplicación de ejemplo he agregado una imagen como recurso. Es una imagen genial y estoy seguro de que todos los usuarios van a quererla así que vamos a guardarla en la biblioteca de medios. La aplicación de ejemplo guarda esta imagen en el método Application_Launching en el archivo App.xaml.cs, aquí está el código para ello.

public static void GuardarImagenBiblioteca(string nombreImagen)
        {
            var biblioteca = new MediaLibrary();
            var imagen = biblioteca.Pictures.Where(p => p.Name == nombreImagen).SingleOrDefault();

            if (imagen == null)
            {
                var recurso = Application.GetResourceStream(new Uri(string.Format(“/31DaysMediaLibrary;component/Images/{0}”,nombreImagen), UriKind.Relative));
                var bitmap = new BitmapImage();
                bitmap.SetSource(recurso.Stream);

                biblioteca.SavePicture(nombreImagen, bitmap.ToStream());
            }
        }

La mayoría de este código esta simplemente trabajando al cargar una imagen. Hay algunas líneas importantes aquí que están usando la Biblioteca de medios. Vamos a ver mas de cerca esas líneas.

var biblioteca = new MediaLibrary();

Esta línea crea una nueva clase de tipo MediaLibrary. Esto es lo que te dará acceso a las propiedades y métodos de la biblioteca de medios.

var imagen = biblioteca.Pictures.Where(p => p.Name == nombreImagen).SingleOrDefault();

Esta línea busca en la biblioteca por cualquier imagen que este ya salvada con el nombre de la imagen. Si esta existe, el código no la guardará de nuevo.

biblioteca.SavePicture(nombreImagen, bitmap.ToStream());

Esta línea guarda el BitmapImage a la biblioteca. Quizá notes que un BitmapImage no tiene normalmente el método ToStream. Pienso que lo tendría utilizando un método extendido para agregarselo. La clase de extensión no tiene nada que hacer con la biblioteca multimedia, pero aquí verás como es que funciona.

public static class ExtensionBitmap
    {
        public static Stream ToStream(this BitmapImage bitmap)
        {
            var writeableBitmap = new WriteableBitmap(bitmap);
            var stream = new MemoryStream();
            writeableBitmap.SaveJpeg(stream, bitmap.PixelWidth, bitmap.PixelHeight, 0, 100);
            stream.Position = 0;
            return stream;
        }
    }

Después de que el código ha sido ejecutado, la imagen estará disponible en la biblioteca de medios. Para mostrar esto en nuestra aplicación de ejemplo, puedes dar clic en el ícono del engrane en la bandeja de la aplicación y la nueva imagen estará disponible para ser seleccionada usando un PhotoChooserTask.

clip_image0046

Obtener una lista de canciones

En la aplicación de ejemplo la pantalla muestra una lista de las canciones que el usuario tiene en la biblioteca de medios. La lista es un ListBox. Un Data Template es definido y es el que enlaza la propiedad Text de los dos TextBlock. Uno despliega el título de la canción y el otro despliega al artista. Aquí esta lo como queda el XAML para el ListBox.

<ListBox
                x:Name=”lstCanciones”
                SelectionChanged=”lstCanciones_SelectionChanged”>
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin=”0,0,0,17″ Width=”432″ Height=”78″>
                            <TextBlock Text=”{Binding Name}” TextWrapping=”Wrap” Style=”{StaticResource PhoneTextExtraLargeStyle}”/>
                            <TextBlock Text=”{Binding Artist.Name}” TextWrapping=”Wrap” Margin=”12,-6,12,0″ Style=”{StaticResource PhoneTextSubtleStyle}”/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

Ajusta el ItemSource a la lista de canciones es bastante simple:

var biblioteca = new MediaLibrary();
lstCanciones.ItemsSource = biblioteca.Songs;

¿Qué mas hay ahí?

Hay algunas otras propiedades de la clase MediaLibrary para considerar:

Álbumes – Es similar a la colección de canciones, pero enlista en su lugar los álbumes

Artistas – Así como la colección de álbumes, esta colección enlista a los artistas de las canciones.

Genres – Esta colección enlista los géneros de las canciones.

Playlists – Esta colección enlista las listas de reproducción que el usuario ha agregado a su biblioteca.

En resumen

Como puedes ver, usar la Biblioteca de medios es bastante sencillo. La mayoría del código en la aplicación de ejemplo esta escrito para usar el contenido, no para acceder a el desde la biblioteca. Hablé acerca de acceder a la colección de canciones y como guardar una imagen en la biblioteca. Discutí unas pocas maneras de usar la biblioteca en tus propias aplicaciones. Estoy seguro que hay  muchas mas formas  de usar este contenido. Diviértete y no puedo esperar a ver tus aplicaciones.

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana, cubriremos la globalización/localización en el artículo y te mostraremos que tan sencillo es incluir esto en tu proyecto Windows Phone. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 27: API del micrófono

December 28th, 2011 No comments

Esta es una traducción de Day 27:Microphone API, puedes encontrarlo aquí en su versión original en inglés.

dia27

Introducción

El reconocimiento de voz o tomar notas es una práctica muy común dependiendo de tu profesión o uso, por ejemplo, es entendido que los dispositivos móviles de hoy ofrecen alguna clase de reconocimiento de palabras y control de la aplicación, ya sean direcciones o marcar un número o el otro uso común, al reproducir música.

La tarea de notas es otro elemento que es útil para ser capaz de capturar audio en el campo para futuras referencias.

El primer paso de todas estas aplicaciones es ser capaz de capturar audio vía el micrófono y procesarlo como sea necesario.

Así que hoy miraremos al API del microfono proveída por Mango y haremos un ejemplo muy sencillo para que inicies.

¿Qué es lo que esta involucrado?

Haremos lo mínimo, necesitaremos grabar audio y salvarlo para su reproducción.

Los siguientes puntos clave deberán ser notados:

1. Clase Microphone: Esta es la clase proveída por el espacio de nombres Microsoft.Xna.Framework.Audio que nos permite el acceso a la API del micrófono.

2. Evento publico EventHandler<EventArgs> BufferReady: Este es un evento que se manifiesta cuando el micrófono esta listo para librerar el audio almacenado. Necesitamos manejar esta evento y almacenar el audio para una reproducción posterior.

3. Microphone.Start: Como el nombre indica, lo llamamos para iniciar la grabación.

4. Microphone.Stop: Lo llamamos para detener la grabación. Un punto importante para considerar es que al llamar a Microphone.Stop inmediatamente limpiara el buffer.

Como verás en la aplicación, no llamamos al método Stop inmediatamente cuando el usuario abra el micrófono o de clic en el botón de reproducir. En lugar de eso, dejamos al micrófono levantar el evento de BufferReady con la duración del buffer seleccionada para capturar hasta el último bit de información de audio antes de detener la grabación.

using Microsoft.Xna.Framework –> Como debiste haber adivinado desde el espacio de nombres, requerimos una referencia al framework de Xna. El API del micrófono es parte del framework de XNA y requiere la simulación de juego de Xna. Si no estás familiarizado con XNA, XNA es un framework muy enriquecido proveido por Microsoft para aplicaciones destinadas para juegos y gráficas.

Entendiendo el ejemplo

Prerequisitos: Instala las herramientas de Mango http://create.msdn.com , esto te dará el Windows Phone SDK y Visual Studio Express 2010 que necesitas para desarrollar aplicaciones para Windows Phone.

1. Lanza Visual Studio, navega a la solución y ábrela. La aplicación esta creada usando Silverlight for Windows Phone. Corre el proyecto y despliega la aplicación en el emulador. Verás la siguiente pantalla cuando la aplicación termine de cargar.

clip_image0023

2. El elemento de la pantalla:

a. El botón de micrófono es una palanca la cual comienza y detiene al micrófono.

b. El botón de reproducir es usado para escuchar el sonido guardado.

c. Hay tres sliders para ajustar el volumen, extracción y tono del sonido al ser reproducido.

3. Como funciona:

a. Toca el micrófono para iniciar la grabación. Puedes detener la grabación al tocar el micrófono de nuevo o alternativamente al tocar el botón de reproducir.

b. Ajusta el volumen, prueba el sonido al cambiar los valores de los sliders al reproducir el sonido.

Entendiendo el código

Aquí están las declaraciones iniciales:

private Microphone microfono = Microphone.Default;
private MemoryStream stream = new MemoryStream();
private SoundEffectInstance sonidoGrabado;
private byte[] buffer;
bool estaReproduciendoSonido = false;
string rutaImagenMicrofonoDetenido = “Imagenes/stopped.png”;
string rutaImagenMicrofonoIniciado = “Imagenes/114px-Yeti-USB-Microphone.png”;
string rutaImagenBotonPlayPausadoLight = “Imagenes/light.appbar.transport.pause.rest.png”;
string rutaImagenBotonPlayPausadoDark = “Imagenes/dark.appbar.transport.pause.rest.png”;
string rutaImagenBotonPlayLight = “Imagenes/light.appbar.transport.play.rest.png”;
string rutaImagenBotonPlayDark = “Imagenes/dark.appbar.transport.play.rest.png”;
bool grabacionDetenida = false;
bool reproducirSonido = false;
bool streamDesechado = false;
bool esTemaOscuro = ((Visibility)Application.Current.Resources["PhoneDarkThemeVisibility"] == Visibility.Visible);

Estaremos usando un objeto de la clase SoundEffectInstance para reproducir el sonido grabado. Podríamos también haber usado un SoundEffect, sin embargo al usar la clase SoundEffectInstance nos permitirá rastrear el estado (reproduciendo o detenido).

La otra declaración aquí es para un objeto MemoryStream. El buffer del micrófono es constantemente escrito en un memorystream a menos que la reproducción sea deseada. En este momento, ingresamos el contenido del memorystream al objeto SoundEffectInstance para reproducir.

Inicialización:

public MainPage()
{
InitializeComponent();
DispatcherTimer temporizador = new DispatcherTimer();
temporizador.Interval = TimeSpan.FromMilliseconds(33);
temporizador.Tick += new EventHandler(temporizador_Tick);
temporizador.Start();
AjustarMicrofono();
SoundEffect.MasterVolume = 1.0f;
AjustarImagenBotonReproducirBasadoEnTema();
}

El punto principal para ver aquí es el ciclo que hemos creado usando un DispatcherTimer. Este ciclo es esencial para capturar el audio desde el micrófono.

Ajustamos la imagen para el botón de reproducir basado en el tipo de tema que esté seleccionado.

Hasta ahora también ajustamos los valores del micrófono para nuestra aplicación, como sigue:

private void AjustarMicrofono()
{
if (Microphone.Default == null)
{
return;
}

microfono.BufferDuration = TimeSpan.FromMilliseconds(500);
buffer = new byte[microfono.GetSampleSizeInBytes(microfono.BufferDuration)];
stream.SetLength(0);

microfono.BufferReady += microfono_BufferReady;

ImageBrush pincel = new ImageBrush();
pincel.ImageSource = new BitmapImage(new Uri(rutaImagenMicrofonoDetenido, UriKind.Relative));
pincel.Stretch = Stretch.Uniform;
btnGrabar.Background = pincel;
}

La duración del buffer es de medio segundo y después usamos un método llamado GetSampleSizeInBytes y pasamos la duración del buffer para obtener el tamaño real de este. Esto es importante para asegurar una captura de audio fluida-

Enlazamos el evento de Buffer Ready y ajustamos la imagen preestablecida del micrófono detenido.

¡Estamos listos para comenzar a grabar!

Grabar audio:

Cuando el usuario de clic sobre el botón del micrófono, el siguiente código es llamado:

private void btnGrabar_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (estaReproduciendoSonido)
{
return;
}
streamDesechado = false;

if (microfono.State == MicrophoneState.Stopped)
{
ImageBrush pincel = new ImageBrush();
pincel.ImageSource = new BitmapImage(new Uri(rutaImagenMicrofonoIniciado, UriKind.Relative));
pincel.Stretch = Stretch.Uniform;
btnGrabar.Background = pincel;
if (sonidoGrabado != null) sonidoGrabado.Stop();
stream.SetLength(0);
grabacionDetenida = false;
microfono.Start();

}
else if (microfono.State == MicrophoneState.Started)
{
grabacionDetenida = true;
ImageBrush pincel = new ImageBrush();
pincel.ImageSource = new BitmapImage(new Uri(rutaImagenMicrofonoDetenido, UriKind.Relative));
pincel.Stretch = Stretch.Uniform;
btnGrabar.Background = pincel;
btnReproducir.IsEnabled = true;
}

reproducirSonido = false;
AjustarImagenBotonReproducirBasadoEnTema();
estaReproduciendoSonido = false;
}

Aquí suceden unas cosas:

1- El micrófono es detenido: Si el micrófono es detenido necesitamos comenzar a hacerlo grabar. Ajustamos el fondo del botón del micrófono. Después reiniciamos el MemoryStream para limpiar nuestro audio grabado previamente. Checamos  y detenemos el audio a reproducir.

Pasos muy sencillos de seguir. Ahora necesitamos llamar al método Microfono.Start(). El resto de los pasos están basados en la UI y diseño de la aplicación.

2. El micrófono esta grabando: Primero necesitamos detener la grabación. Si reactivas la nota de arriba, no podemos llamar al método Microfono.Stop() inmediatamente mientras que toda la información grabada no haya sido desechada del MemoryStream. Así que usamos variables booleanas para mantener un registro y diferir la acción de detener en el evento DispatchTimer.

Dos cosas necesitan pasar aquí. Primero, necesitamos dejar el buffer del micrófono listo para lanzar al inicio de modo que podamos leer el último bit del audio y después necesitamos lanzar la reproducción. Manejamos esto como se muestra.

void microfono_BufferReady(object sender, EventArgs e)
{
microfono.GetData(buffer);
stream.Write(buffer, 0, buffer.Length);

if (grabacionDetenida)
{
stream.Flush();
streamDesechado = true;
microfono.Stop();
}
}

En el evento anterior, verificamos si la grabación ha sido detenida usando nuestras variables booleanas y después llamamos al método Stream.Flush(). Esto desecha la información restante del MemoryStream. Después detenemos el micrófono.

Sin embargo, no podemos lanzar la reproducción de audio en este evento, Esto es manejado por el “tick” del temporizador como se muestra en seguida:

void temporizador_Tick(object sender, EventArgs e)
{
try { FrameworkDispatcher.Update(); }
catch (Exception ex)
{
throw ex;
}

if (true == estaReproduciendoSonido)
{
if (sonidoGrabado.State != SoundState.Playing)
{
ResetearAjustesReproduccion();
}
}
else
{
if (reproducirSonido && streamDesechado)
{
reproducirSonido = false;
if (stream.Length > 0)
{
AjustarImagenBotonPausaBasadoEnTema();
Thread hiloSonido = new Thread(new ThreadStart(iniciarReproduccion));
hiloSonido.Start();
}
}
}
}

El evento es llamado cada 33 milisegundos. Así que estará bastante ajustado para que el usuario reproduzca el sonido sin ningún problema. La ventaja, por supuesto es que podemos reproducir el audio entero antes de dejar que sea cortado.

Checamos si es momento de grabar y ver si el stream ha sido desechado. Si es así, iniciamos un nuevo hilo para la reproducción de audio. Este es un punto importante para notar.

Estamos lanzando la reproducción de la cinta en un hilo diferente para permitir a la UI actualizarse. Esto significa que cualquier código dentro de nuestra rutina de reproducción que escoja actualizar los elementos de la interfaz tiene que hacerlo al llamar al DispatchBeginInvoke como se muestra abajo.

Reproducir el audio

private void iniciarReproduccion()
{
SoundEffect sonido = new SoundEffect(stream.ToArray(), microfono.SampleRate, AudioChannels.Mono);
sonidoGrabado = sonido.CreateInstance();

estaReproduciendoSonido = true;
Dispatcher.BeginInvoke(() =>
{
sonidoGrabado.Pitch = (float)sldPitch.Value;
sonidoGrabado.Pan = (float)sldPan.Value;
sonidoGrabado.Volume = (float)sldVolumen.Value;
}
);
sonidoGrabado.Play();
}

Creamos un objeto de la clase SoundEffectInstance  alimentándolo del stream de audio capturado, el rango de ejemplo del micrófono y el canal de audio.

Dado que deseamos usar los sliders para ajustar el volumen, pitch y pan, tenemos que usar de nuevo un Dispatcher.BeginInvoke dado que ellos están en un hilo diferente.

Finalmente llamamos al botón reproducir.

En resumen

Es bastante simple crear una aplicación que registre audio. Podemos extender esta aplicación para guardar el audio grabado en el almacenamiento aislado y darle un título elegido por el usuario. Podemos agregar una vista de lista de las grabaciones del almacenamiento aislado y hacer una pequeña aplicación de notas de voz.

Los pasos básicos de la grabación de audio son:

a)Enlaza un evento al micrófono preestablecido para capturar el audio.

b)Escribe el audio en un stream

c)Cuando el usuario detenga la grabación, desecha el stream y almacénalo o reprodúcelo.

Podemos también extender esta aplicación tomando el audio grabado y mandándolo a un servicio de traducción y capturar comandos.

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana Jeff Fansler estará cubriendo la clase MediaLibrary y como podemos usarla para aprender mas acerca de la librería de música del usuario en su teléfono. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 26: Transferencia de archivos en segundo plano

December 26th, 2011 No comments

Esta es una traducción de Day 26: Background File Transfer, puedes encontrarlo aquí en su versión original en inglés.

dia26

Ayer creamos un proyecto usando un Background Agent, uno de los nuevos elementos multitarea nuevos en Windows Phone 7.5. Hoy usaremos el Background File Transfer para realizar la descarga de un archivo que continua incluso cuando nuestra aplicación no esté corriendo. Descargaremos un video desde Channel 9 y lo reproduciremos cuando esté completado.

Comenzando

Lanza Visual Studio y crea un nuevo proyecto. Debajo de Silverlight for Windows Phone, selecciona Windows Phone Application. Nombra la aplicación como gustes.

clip_image002_thumb3

Has creado la aplicación principal. Será responsable para:

1) Iniciar nuestra descarga del video

2) Desplegar el estado de la descarga

3) Reproducir el video una vez que se haya completado

Crear la aplicación

Ahora es tiempo de juntarlo todo. Abre MainPage.xaml y agrega dos botones para descargar y reproducir el video. Después, agrega dos TextBlocks para desplegar el progreso y estado.

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
            <Button x:Name=”btnIniciar” Click=”btnIniciar_Click” Content=”Iniciar descarga” Margin=”0,101,0,0″ VerticalAlignment=”Top”/>
            <Button x:Name=”btnReproducir” Click=”btnReproducir_Click” IsEnabled=”False” Content=”Reproducir video” Margin=”0,225,0,0″ VerticalAlignment=”Top”/>
            <TextBlock x:Name=”txtProgreso” Margin=”8,0,8,258″ VerticalAlignment=”Bottom”/>
            <TextBlock x:Name=”txtEstado” Margin=”8,0,8,159″ VerticalAlignment=”Bottom” Height=”0″/>
        </Grid>

No incluiré el MainPage.xaml entero aquí, pero está disponible en la solución al final. Primero, definimos algunas variables para mantener la ubicación de nuestro video a descargar, la ubicación donde guardaremos el video y la taza de transferencia actual.

private const String ubicacionArchivo = “shared/transfers/MiVideoDescargado.mp4″;
        private Uri direccionVideoDescarga = new Uri(“http://video.ch9.ms/ch9/02df/0a2774a9-a010-4b9b-b654-9f88014102df/xboxCompanion_med_ch9.mp4″);
        private Uri direccionGuardarArchivo = new Uri(ubicacionArchivo, UriKind.RelativeOrAbsolute);
        private BackgroundTransferRequest solicitudActual = null;

Nota que cuando se descarga directamente al Almacenamiento Aislado, todas las descargas deben ir hacía shared/transfers/. Estaremos descargando un video desde Channel9 y guardarlo como “MiVideoDescargado.mp4”.

Cuando un usuario da clic en “Iniciar descarga”, crearemos un nuevo BackgroundTransferRequest y le diremos lo que queremos descargar y donde queremos guardar lo descargado. De forma preestablecida, una descarga puedes solo ser realizada cuando el dispositivo esta conectado y tiene una conexión Wi-Fi. Ajustamos esto con BackgroundTransferRequest.TransferPreferences a AllowCellularAndBattery. Finalmente, agregamos nuestra solicitud al BackgroundTransferService.

solicitudActual = new BackgroundTransferRequest(direccionVideoDescarga, direccionGuardarArchivo);
            solicitudActual.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
            BackgroundTransferService.Add(solicitudActual);

También necesitamos ser notificados del estado de la solicitud y el progreso para mostrarlo en nuestra UI. Podemos suscribirnos a los cambios manejando los eventos TransferProgressChanged y TransferStatusChanged.

if (solicitudActual != null)
            {
                solicitudActual.TransferProgressChanged += solicitudActual_TransferProgressChanged;
                solicitudActual.TransferStatusChanged += solicitudActual_TransferStatusChanged;
            }

Cuando somos notificados por ese eventos, podemos checar muchas propiedades en nuestro BackgroundTransferRequest para ver el estado actual de la descarga:

* BytesReceived / TotalBytesToReceive para el progreso de la descarga

* BytesSent / TotalBytesToSend para el progreso de una carga

* TransferStatus para el estado actual de la descarga (transferencia, completado, etc.)

* TransferError para información acerca de un archivo transferido

Nota que no importa si la transferencia fue exitosa, TransferStatus lo reportara a Completed cuando termine. Debido a esto, una vez que TransferStatus reporte su estado a Completed, deberías checar TransferError para ver si un error ocurrió.

Cuando la transferencia este completada, deberías removerlo del BackgroundTransferService:

BackgroundTransferService.Remove(solicitudActual);

Finalmente, uno de los aspectos mas truculentos de implementar un background file transfer, es lidiar con el cierre de tu aplicación. Cuando reingreses a la aplicación, necesitamos que nuestro estado siga cargando, incluso cuando solicitudActual vaya a ser nula y nuestros eventos no estén mas entrelazados. Para lidiar con esto, reseteamos nuestra solicitudActual y enlazamos los eventos en OnNavigatedTo:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            foreach (BackgroundTransferRequest solicitud in BackgroundTransferService.Requests)
            {
                solicitudActual = solicitud;
                break;
            }

            IniciarSolicitudParaTransferencia();
            IniciarManejadoresParaTransferencia();
            RefrescarDireccionTransferencia();
        }

Ya funcional, este ejemplo es bastante simple. Es recomendado que también cheques la vista general del Background File Transfer en MSDN para una mas completa referencia.

Correr la aplicación

Nota que nuestra aplicación esta lista para correr, despliégala en el emulado o en un dispositivo y ejecútala. Da clic en “Iniciar descarga” y deberás ver el progreso de la descarga reportado:

clip_image0032

Presiona el botón de “Iniciar” y deja a la aplicación. Espera un poco y después reingresa a la aplicación. Deberás ver que el progreso de la descarga ha continuado incluso cuando la aplicación no estaba corriendo. Una vez que el estado este completado, puedes dar clic en “Ver video” para ver el video que fue descargado.

En resumen

Hoy creamos un BackgroundTransferRequest que descarga un video. Cuando se hace la solicitud de transferencia por tu cuenta, ten en cuenta que cubrimos.

* Iniciar un BackgroundTransferRequest y agregalo al BackgroundTransferService para iniciar una carga o descarga.

* Guarda las descargas en share/transfers al guardar en el Almacenamiento Aislado.

* Maneja la BackgroundTransferRequest. TransferProgressChanged y BackgroundTransferRequest. Los eventos TransferStatusChanged son notificados de cambios en el estado de transferencia.

* Cuando BackgroundTransferRequest y TransferStatus este completo, recuerda checar BackgroundTransferRequest y TransferError para ver si la transferencia fue exitosa.

* Manejar escenarios donde el usuario deje y regrese a la aplicación.

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana. Parag Joshi esta de vuelta para discutir la API del micrófono y como podemos usarla para capturar audio desde un dispositivo Windows Phone. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 25: Background agents

December 25th, 2011 No comments

Esta es una traducción de Day 25: Background Agents, puedes encontrarlo aquí en su versión original en inglés.

dia25

Hoy, vamos a darle un vistazo a una de las capacidades multitarea nuevas en Windows Phone Mango. El entorno completo de multitarea abarca muchos nuevos elementos:

* Background Agents

* Background File Transfer

* Background Audio Playback

* Scheduled Notifications

* Fast Application Switching

Aquí nos enfocaremos en los Background Agents. Mientras que la transferencia de archivos y tarea de reproducción de audio cubren escenarios específicos, no permiten un código personalizado para ser ejecutados. Aquí es donde entran los agentes en segundo plano.

Hay dos tipos de agentes de segundo plano: Periodic y Resource Intensive. Los agentes de recursos intensivos están hechos para tareas que consumirán un monto grande de recursos del sistema pero con muchas limitaciones para cuando ellos quieran correr. Los agentes periódicos corren mas frecuentemente y con menos restricciones, pero están hechos para tareas que sean ligeras en consumo de recursos. Para entender completamente las diferentes limitantes y beneficios de cada uno,visita la página de MSDN.

Una tarea periódica puede hacer algo corto y simple, así como refrescar un RSS o actualizar tu live tile. Una tarea exigente de recursos puede hacer algo que requiera mas tiempo y ancho de banda, como sincronizar o atrapar grandes montos de datos desde un servicio en la nube.

Vamos a hacer un agente periódico que actualizará el live tile de tu aplicación con el último momento en el que nuestra tarea personalizada se ejecutó.

Comenzando

Lanza Visual Studio 2010 y crea un nuevo proyecto. Debajo de Silverlight for Windows Phone, selecciona Windows Phone Application.

clip_image0021

Ya has creado la aplicación principal. Esta será responsable de dos cosas:

1) Tener un live tile que el agente de segundo plano puede actualizar con información

2) Iniciar y detener el agente de segundo plano

El agente de segundo plano por sí mismo, debe vivir en su proyectos propio especial. Agrega un nuevo proyecto a tu solución, seleccionando Windows Phone Scheduled Task Agent. Nómbralo MiAgente. Este proyecto contendrá el código personalizado que correrá en segundo plano y actualizará el live tile.

clip_image0042

Finalmente, y esto es importante, ve a tu proyecto principal y agrega una referencia a MiAgente. Esto automáticamente te permitirá registrar tu agente desde dentro de la aplicación. También nota esta entrada automáticamente creada en el WMAppManifest.xml:

<Tasks>
      <DefaultTask Name=”_default” NavigationPage=”MainPage.xaml” />
      <ExtendedTask Name=”BackgroundTask”>
        <BackgroundServiceAgent Specifier=”ScheduledTaskAgent” Name=”MiAgente” Source=”MiAgente” Type=”MiAgente.ScheduledAgent” />
      </ExtendedTask>
</Tasks>

Crear la aplicación

Ahora es tiempo de juntarlo todo. Abre el MainPage.xaml y agrega dos botones, uno para iniciar el agente y el otro para detenerlo.

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
            <Button x:Name=”btnIniciar” Content=”Iniciar agente” Height=”90″ Margin=”8,53,8,0″ VerticalAlignment=”Top” Click=”btnIniciar_Click”/>
            <Button x:Name=”btnDetener” Content=”Detener agente” Height=”90″ Margin=”8,147,8,0″ VerticalAlignment=”Top” Click=”btnDetener_Click”/>
</Grid>

En el archivo MainPage.xaml.cs enlaza los botones para iniciar y detener al agente

using Microsoft.Phone.Controls;
using Microsoft.Phone.Scheduler;
using System;

namespace Dia_25_Agentes
{
    public partial class MainPage : PhoneApplicationPage
    {
        private const string nombreTarea = “MiAgente”;

        public MainPage()
        {
            InitializeComponent();
        }

        private void btnIniciar_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            IniciarAgente();
        }

        private void btnDetener_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            DetenerAgenteSiIniciado();
        }

        private void IniciarAgente()
        {
            DetenerAgenteSiIniciado();

            PeriodicTask tarea = new PeriodicTask(nombreTarea);
            tarea.Description = “Este es un agente personalizado para el ejemplo”;
            ScheduledActionService.Add(tarea);
#if DEBUG
            // Si estamos depurando, intentar iniciar la tarea inmediatamente
            ScheduledActionService.LaunchForTest(nombreTarea, new TimeSpan(0, 0, 1));
#endif
        }

        private void DetenerAgenteSiIniciado()
        {
            if (ScheduledActionService.Find(nombreTarea) != null)
            {
                ScheduledActionService.Remove(nombreTarea);
            }
        }
    }
}

Nota que al crear nuestro agente personalizado, estamos creando una nueva PeriodicTask. Usamos entonces el nombre como identificador al encontrar y detener al agente. Nota también que especificamos PeriodicTask.Description (es un campo requerido y aparecerá en Settings | Background Tasks debajo del nombre de nuestra aplicación).

Crear el agente de segundo plano

En el proyecto MiAgente, abre ScheduledAgent.cs y agrega el siguiente código:

protected override void OnInvoke(ScheduledTask task)
        {
            ActualizarTileAplicacion(ObtenerUltimoMensajeDeActualizacion());
        }

        private string ObtenerUltimoMensajeDeActualizacion()
        {
            return string.Format(“Ultima: {0}”, DateTime.Now);
        }

        private void ActualizarTileAplicacion(string message)
        {
            ShellTile appTile = ShellTile.ActiveTiles.First();
            if (appTile != null)
            {
                StandardTileData tileData = new StandardTileData
                {
                    BackContent = message
                };

                appTile.Update(tileData);
            }
        }
La clase ScheduledAgent tiene un método sobrecargado importante OnInvoke. Aquí es donde tu agente ejecutará su tarea en segundo plano. Si tu tarea esta completada y no necesitas mas a tu agente para ejecutarse, puedes llamar al método NotifyComplete() para verificar que la tarea ha sido satisfactoriamente completada o Abort() para verificar que estás cancelando la tarea. Para mantener la tarea corriendo a un intervalo, simplemente no llames a ninguno, que es lo que estamos haciendo aquí.

Correr la aplicación

Ahora que nuestra aplicación esta lista para ejecutarse, despliégala en el emulador o en un dispositivo. Da un clic para iniciar el agente de segundo plano. Deja a la aplicación y regresa a la lista de aplicaciones. Presiona y mantente sobre la aplicación, escoge “anclar a inicio”. Cuando veas el tile en tu página de inicio deberías eventualmente ver a la aplicación girar, revelando la última vez que fue actualizada.

clip_image005

En resumen

Así que hoy creamos nuestro propio Background Agent personalizado que actualiza un live tile. Cuando hagas los tuyos por tu cuenta mantén en cuenta que cubrimos:

* Los agentes de segundo plano te permiten ejecutar código personalizado mientras tu aplicación no está corriendo.

* Hay dos tipos de agentes de segundo plano – periódico y de recursos intensivos.

* Las tareas periódicas son para tareas que tienen bajo consumo de recursos, y como resultado tienen menos restricciones que las tareas de recursos intensivos.

* Los agentes de segundo plano necesitan su propio proyecto, el cual debería ser agregado como una referencia de proyecto a la aplicación que iniciará el agente.

* En tu agente necesitas el método sobrecargado OnInvoke()

* Cuando tu tarea esté completa necesitas llamar a NotifyComplete() o Abort()

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana vamos a mirar a otro elemento multitarea llamado Background File Transfer que nos permitirá descargar o subir archivos mientras que nuestra aplicación no esté corriendo. Nos vemos

Categories: Tutoriales, WP7 Tags:

Día 24: Herramienta de rendimiento

December 24th, 2011 No comments

Esta es una traducción de Day 24: Performance Tools, puedes encontrarlo aquí en su versión original en inglés.

dia24

El rendimiento es un aspecto importante para todas la aplicaciones, especialmente aplicaciones que corren con necesidad de recursos abundantes, los dispositivos confían en la red. Como un usuario, es relativamente fácil decir cuando una aplicación en ejecución es “lenta”; lo que no es fácil es identificar la causa de los problemas de rendimiento. Hacer cambios al código fuente sin entender el efecto en rendimiento puede llevarte a una reconstrucción innecesaria y hacer los problemas potenciales incluso peores.

¿Qué hacer? Con el lanzamiento de Windows Phone Mango, podemos ahora fácilmente identificar el origen de los problemas de rendimiento de nuestra aplicación (todo el camino hacia las funciones que están causando los problemas). Ingresa a la herramienta de perfil. Puedes usar la nueva herramienta para ayudar a identificar detalles con el rendimiento en tu aplicación, incluyendo consumo de memoria, complejidad en los árboles visuales, tiempo de lanzamiento de la aplicación e identificación de funciones de larga duración.

Para correr la sesión de análisis de rendimiento, abre tu proyecto Windows Phone en Visual Studio y selecciona “Stat Windows Phone Performance Analysis” desde el menú de depuración o presiona el atajo de teclas ALT-F1.

image_thumb2

Asegúrate de que estás lanzando el perfilador de Windows Phone y no el perfilador de .NET, el cual también esta encontrado en el menú “Debug”, listado como “Start performance analysis (ALT-F2)”.

Esta primera cosa que verás es una página preguntándote que selecciones el tipo de análisis que quieras hacer. A menos que sepas específicamente que hay un problema de consumo de memoria, deberás comenzar con el análisis de Ejecución:

image_thumb111

Al dar clic en el enlace de “Launch Application” comenzará inmediatamente tu aplicación ya sea en el emulador o en el dispositivo con todo el monitoreo de código agregado a tu sesión. Una vez que la aplicación haya comenzado, navega por toda ella ejercitando esos elementos en tu aplicación que son las mas críticas de rendimiento o los que van a ser frecuentemente usados por tus usuarios. Así como pongas tu aplicación por sus fases, el monitoreo de información será automáticamente coleccionado y registrado por Visual Studio para una revisión posterior.

Una vea que tu sesión de pruebas este completa, regresa a Visual Studio y selecciona el enlace de “Stop Profiling”.

image_thumb12

Hasta ahora, Visual Studio guardará toda la información de rendimiento en un archivo .SAP y agregará ese archivo a tu proyecto. Este archivo será anclado a tu proyecto, así como la fecha y hora de la prueba de ejecución (por ejemplo, DatabaseForMango_2011_11_14_17_59_27.sap”. Este registro puede ser revisado ahora, o guardado para una revisión posterior. La vista principal de los resultados esta ajustada a las gráficas que son elaboradas. Estas gráficas representan un número de medidas diferentes que están apiladas en la cima de cada una para dar una vista de tipo “timeline” del rendimiento de tus aplicaciones.

image_thumb51

Empezando desde la cima, estas gráficas muestran

* Frame Rate: Esto muestra el rango de cuadros registrados para cada uno registrado en la UI. Los números aquí son potenciales focos de problemas que advierten para mayor investigación.

* CPU Usage: Muestra el consumo del CPU durante diferentes partes de la aplicación.

- Las barras verdes representan el hilo de la UI – Uno al cual vigilar mucho dado que el alto uso del hilo de la UI causa a esta que de vuelva poco responsiva al ingreso de datos del usuario. Cualquier valor superior a 50% es un problema potencial en el área.

- Las barras azules representan los hilos de la aplicación – Esto incluye a los hilos de segundo plano creados por el usuario y el hilo de composición (mas alto es mejor, comparado con el hilo de la UI)

- Las barras grises representan los hilos del sistema – Estos son hilos que  NO son parte de tu aplicación, pero representan cosas como tareas de segundo plano, etc.

- Las barras blancas representan los hilos desocupados – Como el “proceso inactivo del sistema” mostrado en el administrador de tareas de Windows, esto representa el porcentaje del CPU disponible. Un número mayor significará una UI mas responsiva.

* Uso de memoria en MB: Vigila esto si tienes mas de 90 MB en cualquiera y corre la prueba siguiente – 90 MB es el límite para pasar la certificación para pasar al Marketplace.

* Animaciones: Una S es desplegada en cada cuadro donde una animación es lanzada.

- Rojo representa una animación enlazada a CPU (estas son malas dado que corren en el hilo del CPU e impactan directamente el rendimiento de la UI)

- Morado representa una animación enlazada a GPU (estas son buenas dado que corren en el hilo del Compositor y no afectan el rendimiento de la UI).

* Image Loads: Una “I” se mostrará para mostrar el cuadro para indicar cuando es cargada una imagen en la memoria.

* Eventos de colección de basura: Una “G” se mostrará para indicar un punto en el cual el colector de basura este corriendo.

Para ver los detalles de la información que esta alimentando la gráfica simplemente usa el puntero para seleccionar la región de la gráfica conteniendo estos cuadros que después quieres filtrar. La sección mas baja, referida como sección de Detailed Performance Analysis, poblará con mensajes de Advertencia e Información que resalte áreas de interés para los cuadros seleccionados.

image_thumb3

Desde esta imagen, puedes ver que dos advertencias específicas son llamadas relacionadas al rango de problemas. Por ejemplo – la primer advertencia en la imagen superior contiene la siguiente información:

Advertencia: Una velocidad muy baja potencialmente causado por un costo de diseño alto.

El tiempo de diseño total (0.35 segundos) es alto. El elemento System.Windows.Controls.ScrollViewer : ScrollViewer tomó la mayoría de tiempo en diseño y esta contribuyendo a una baja velocidad de marcos. Esto puede ser porque las animaciones enlazadas al CPU estan causando actualizaciones de diseño. Ve al menú de Advertencias de Rendimiento en la barra de navegación y selecciona la vista de marcos. Navega entre los cuadros al dando clic en el encabezado de la columna de tiempo del CPU y selecciona los marcos con el mayor tiempo de CPU. Desde la vista de marcos, selecciona la opción Visual Tree e identifica System.Windows.Controls.ScrollViewer : ScrollViewer en el arbol.

La advertencia llama a un bajo nivel de marcos basados en como está construido el diseño relativo al ScrollViewer. La acción sugiere que deberíamos ir al menú de advertencia de rendimiento y seleccionar la vista de cuadros. Si miras mas de cerca a la sección de Rendimiento Detallado, verás que el texto derecho a las advertencias de rendimiento es un botón que controla un menú desplegable conteniendo muchas opciones debajo de ella en la cual podemos ir hacía abajo para mas información. Si escoges la opción “Frames”, verás algo como esto.

image_thumb41

Esta lista de marcos seleccionados muestra que muchos de ellos tienen un uso de CPU cercano al 50% (¡en este caso es incluso cercano al 80%!). Al seleccionar ese marco y yendo de regreso al menú de navegación a un lado del elemento de marcos desde antes, muestra que aún hay mas niveles de detalle al cual podemos ir para un marco en particular. Selecciona cada uno de los elementos para obtener mas información acerca de que es lo que esta pasando con un elemento en particular. Mirar a los elementos así como a la opción “Functions” te permitirá ver que métodos están llamados en tu aplicación y proveerá los enlaces de vuelta a tu código fuente de esos métodos desde la aplicación que están siendo ejecutados. Puedes igualmente el Árbol visual, tipos de elementos y actualizaciones de cache. Estos mensajes de error, combinados con la guía correcta dada en donde mirar por problemas y la habilidad de la herramienta para que puedas ir hacia la raíz te da una gran vista en tu aplicación para descubrir problemas potenciales problemas y arreglarlos antes de enviar tu aplicación al Marketplace para su certificación.

Ahora que hemos visto como trabaja la herramienta, aquí hay un par de tips para usar lo que te ayudará al hacer tu aplicación mas veloz.

* Inicia con las pruebas de Ejecución de rendimiento para ver si hay algunos detalles con la memoria, como se indicó en la gráfica de consumo de memoria. Si descubres lugares donde tu aplicación está consumiendo cerca de 90 MB de memoria, corre una segunda prueba enfocándote específicamente en los ajustes de memoria. Normalmente encontrarás que los detalles de rendimiento pueden ser diagnosticados con esta primera prueba, así que solo usa la segunda prueba cuando los problemas de memoria se hayan superado.

* No olvides probar el FAS, Tombstoning y los correspondientes procesos de activación – todos estos sin partes importantes de tu aplicación-. Para forzar el Tombstoning en tu aplicación cuando presionas el botón de inicio, ve a las propiedades de tu proyecto debajo de la tabla Debug y selecciona “Tombstone upon deactivation while debugging”. De otra forma, tu aplicación se irá de manera pre establecida a FAS.

* Siempre prueba el rendimiento en un dispositivo – el rendimiento de tu laptop no se comparará con el rendimiento de tu dispositivo. Esto nos hace recordar la frase de “no vamos a instalar esta aplicación en tu laptop”. El dispositivo Windows Phone es mucho mas reducido de recursos que la típica estación de trabajo para desarrollo, así que la memoria y rendimiento estarán mas adaptados en el dispositivo que en el emulador. Correr estas pruebas en el dispositivo funciona de la misma forma que la depuración tradicional en el dispositivo (solo cambia el objeto de pruebas de “Windows Phone Emulator” a “Windows Phone Device” en la barra de herramientas estándar de Visual Studio).

En resumen

Aquí hay algunos enlaces para recursos adicionales en el análisis de rendimiento de Windwos Phone:

* Windows Phone Performance Analysis

* How to: Capture and Analyze Performance Data Using Windows Phone Performance Analysis

* How to: Identify and Fix Common Performance Issues Using Windows Phone Performance Analysis

Mañana, Gary Johnson estará escribiendo acerca de los agentes de segundo plano, y como podemos utilizar este nuevo elemento de Windows Phone 7.5 para ejecutar código cuando nuestra aplicación no esta corriendo. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 23: Modelo de ejecución

December 23rd, 2011 No comments

Esta es una traducción de Day 23: Execution Model, puedes encontrarlo aquí en su versión original en inglés.

dia23

Vamos poniéndonos de acuerdo, nuestros smartphones son bastante inteligentes estos días. Pero los correos electrónicos, integración social, juegos y aplicaciones toman un buen tajo comparativamente del pequeño sistema de procesamiento y memoria, pero aún mas importante, la vida de la batería. Es además crucial para cualquier sistema operativo móvil y sus aplicaciones de terceros ser muy responsable al optimizar el uso de recursos en un smartphone, así como proveer la experiencia de usuario mas fluida y responsable posible. Aquí es donde el Execution Model viene en la jugada y se vuelve importante para entender en los varios eventos/estados durante el ciclo de vida de una aplicación. En este artículo hablaremos de como se ve el modelo de ejecución para Windows Phone y que ha cambiado con el lanzamiento de Mango para los consumidores y desarrolladores.

La manera de Windows Phone

Mientras hablamos de las varias partes de Windows Phone y sus aplicaciones de terceros todo el día, el teléfono toma un muy bien definido enfoque para administrar el ciclo de vida de una aplicación desde su lanzamiento hasta su finalización. El modelo de ejecución simplemente permite solo una aplicación para correr en primer plano a la vez. Dado que debemos ver como es benéfico esto para la experiencia de usuario, déjame jugar al abogado del diablo y discutir lo contrario. Sin embargo, incluso si esto fuera posible ¿Puedes realmente poder ver varias aplicaciones correr lado a lado en primer plano en un Windows Phone? ¿No puede ser el tamaño de la pantalla demasiado limitado para tratar de hacer esto? El enfocarse en una aplicación en primer plano simplemente tiene sentido para el factor del teléfono y compromete al usuario en una experiencia envolvente. Aquí es donde llega el estado real con el cual jugar, de forma similar los sistemas operativos Metro permiten a múltiples aplicaciones ancladas trabajando lado a lado en el primer plano, como en las vistas de Windows 8. Pero no estoy de acuerdo.

Así, esta decisión de una aplicación en el primer plano tiene implicaciones en el ciclo de vida de una aplicación. La mayoría de los usuarios de Windows Phone están acostumbrados a moverse entre aplicaciones de terceros y el SO por si mismo por medio del uso de los botones Inicio/Volver, mensajes o tiles. Cada aplicación Windows Phone para por varias fases, cada una exponiendo eventos, mientras pasamos por el tiempo de la aplicación en primer plano. Los detalles a continuación.

Los estados de la aplicación

En esencia, cada aplicación de Windows Phone para por los siguientes estados:

* Running – Este es el tiempo principal en primer plano para cualquier aplicación. El SO y el usuario le dan toda la atención a lo que hace.

* Dormant – Es el momento en el que una aplicación se retira del primer plano e inmediatamente se va a un estado “dormido”. Esta es una nueva mejora en Windows Phone Mango, donde toda la aplicación con su estado e historia son mantenidos intactos en la memoria. El objetivo aquí satisfacer las supremas responsabilidades de las aplicaciones en resumen, el cual es haber salido del primer plano, en caso de que el usuario quiera regresar a la aplicación. Esto es a lo que llamamos Fast Application Switching (FAS) en Windows Phone Mango.

¿Quieres intentarlo? Bien, sin mas que decir, necesitas un Windows Phone corriendo Mango o el emulador mas actual. Salta entre diferentes partes  del SO o aplicaciones de terceros y luego presiona el botón de Regreso y ¡voila! Verás algo como esto ¿Lo ves?

FAS

Lo que estás viendo es el conjunto de aplicaciones en segundo plano, como una especie de pantallazo de las están en el estado Dormant, listas para regresar al primer plano en cuanto las selecciones. Para el consumidor, esto es multi tarea. Para ti como desarrollador, esto es FAS, una reactivación de la aplicación rápida sin que tengas que hacer nada. Bueno excepto por recompilar tus aplicaciones pre Mango usando el último SDK (7.1) de Windows Phone. Esto inmediatamente tiene dos efectos, tu aplicación no muestra el viejo mensaje de “Cargando..” si regresa al primer plano desde el estado en espera y también verás una captura de pantalla de la aplicación. Deberíamos ver un poco de código de prisa.

* Tombstoned – Ahora, como vimos, el runtime de Windows Phone mantiene en la memoria las aplicaciones en hibernación que han estado recientemente en primer plano. Mientras el resumen instantáneo es genial, pero cualquier smartphone tiene disponibilidad de memoria y el SO puede necesitar soporte para realizar alguna operación grande. Adivina que es lo que pasa. Si, las aplicaciones pasan de segundo plano  a un modo de “Último en entrar, primero en salir”. En otras palabras, son desechadas y considerada para no estar consumiendo ningún recurso del sistema mas allá de ese punto. El último estado es no es técnicamente verdad, como lo veremos en un minuto.

Así que ¿cómo afecta el Tombstoning al ciclo de vida de una aplicación? Bueno, si el usuario ha estado usando tu aplicación, y después se va a algún juego que sea exigente de recursos, hay una oportunidad de que eventualmente tu aplicación sea desechada para liberar un poco de memoria para consumo del sistema. Sin embargo, el usuario debería decidir atravesar para llegar de nuevo a tu aplicación después de un tiempo. ¿Cómo se debería comportar tu aplicación? ¿Podemos recordar las cosas que el usuario tenía cuando dejó nuestra aplicación?

La respuesta es SI. Podemos darle absolutamente al usuario la experiencia que pudo venir de regresar como si nunca hubiera dejado tu aplicación y comenzar desde donde se quedó. Para lograr este efecto, sin embargo, necesita que nosotros, lo desarrolladores compartamos alguna responsabilidad para administrar el estado de nuestra aplicación a través de todo su ciclo de vida. En el código que sigue, veremos como podemos “hidratar” el estado de nuestra aplicación fuera del Tombstone, para darle al usuario final la impresión de que la aplicación nunca fue desechada. La verdad es que incluso cuando una aplicación es desechada algo de su información (como un diccionario) acerca del estado de la aplicación  es preservado en memoria por el Sistema Operativo.

* Terminated – Una aplicación en este estado no tiene  ninguna huella en la memoria del SO. Nada, incluyendo diccionarios de estado, de lo cual hablaremos mas tarde, no es preservado y ningún uso subsecuente de la aplicación resultará en una instancia fresca. Una aplicación alcanza este estado después de que ha sido desechada, el usuario navegó de regreso desde la primera página o una excepción no manejada ha matado a la aplicación.

Páginas y Eventos

Antes de movernos en el ciclo de vida de los eventos de la aplicación, vamos a dar un pequeño paso atrás para asegurarnos que nuestros fundamentos están correctos. Todas las aplicaciones Silverlight para Windows Phone corren en una colección de páginas XAML que son cargadas dentro del marco de Windows Phone. Mientras que la aplicación este en primer plan, el usuario es libre de navegar entre páginas dentro de la aplicación. Al presionar el botón de volver, hará que se regrese a la página anterior dentro de la aplicación, hasta que la primera página de la aplicación sea alcanzada y presionarlo ahí hará salir de la aplicación. Nosotros como desarrolladores, no necesitamos hacer nada para hacer que esto pase, mientras que el SO se preocupe de esto automáticamente durante el tiempo principal de la aplicación en primer plano.

Pero considera esto, un usuario esta escribiendo algo de contenido en un control de texto en una página XAML, se distrae y mueve de nuestra aplicación para realizar alguna operación. Cuando vuelve, dos cosas podrán haber pasado. Una, la aplicación pudo haber solo dormido y regresar justo con lo que el usuario estaba escribiendo, aquí no hay nada que tu aplicación necesite hacer para soportar esto, excepto por checar por una API para asegurarse de que tu aplicación estaba “dormida”. En segundo lugar, tu aplicación quizá haya sido desechada y ahora tienes un pequeño problema. Necesitas traer de vuelta a tu aplicación e hidratar el estado del XAML exactamente como el usuario la dejó. Esto es lo que veremos en el código.

Ahora que estamos hablando de los estados de las páginas, es un buen momento para hablar acerca de dos eventos durante el lapso de vida de una página

*OnNavigatedTo – Este evento se dispara cuando la página esta siendo llamada al primer plano para ser desplegada. Esto nos da a los desarrolladores una oportunidad para leer cadenas de consulta pasadas a la página para alimentar a los controles apropiadamente si viene desde Tombstoning.

*OnNavigatedFrom – Este evento se dispara cuando el usuario esta abandonando la página presente para ir hacia otra página dentro de la aplicación o dejando la aplicación completa. En cualquier caso, esto sirve como un buen punto para guardar cualquier información del estado para la página actual, en caso de la restauración quizá sea necesario en el futuro. Veremos estos ejemplos en código.

Diccionarios de datos y estados

Ahora, demos un vistazo a que tipo de información estamos tratando de preservar y alimentar durante nuestro modelo de ejecución de la aplicación. En mi opinión, la información de Windows Phone es de dos tipos.

* Settings and Permanent Data  – Este tipo de información es la cruz de tu aplicación y necesita ser mantenida mientras la aplicación este corriendo. No debemos gastar tiempo en guardar tal información en el almacenamiento aislado, así como archivos/carpetas, o en SQL CE si la información es relacional.

* Page and Transient Data – Esta es prescindible, pero conveniente para guardar información y es la que mejor puede lidiar con la memoria. Este tipo de información podría ser de cualquier tipo abarcando desde información si guardar por el usuario en una página, cualquier VistaModelo o algo de información temporal para el ciclo de vida de nuestra aplicación obtenida desde fuera. Esta es la información que necesitamos manejar cuidadosamente para dar a los usuarios finales la impresión de que nuestra aplicación esta viva y lista par continuar con su ciclo de vida. Ahora tenemos un poco de ayuda. Windows Phone expone un diccionario para cada aplicación y cada página de la aplicación puede ser usada para almacenar un par de información de tipo Key-Value. Este diccionario de estado esta fuera del PhoneApplicationService y debería ser solo usado para almacenar información de estado transitoria. No deberías usar esta propiedad para almacenamiento excesivo porque existe un límite de 2 MB para cada página y 4 MB para la aplicación entera; pero como veremos en el código, es muy útil al mantener el estado durante el modelo de ejecución de la aplicación. Y en esos diccionarios que son mantenidos por el SO incluso después de que la aplicación ha sido desechada. Si la aplicación es reactivada desde Tombstoning, este diccionario de estado será poblado con la información que guardamos en el durante la desactivación de la aplicación, Dado que esta información está presente en memoria, podemos utilizarla para recuperar el estado sin operaciones de archivos que demanden muchos recursos.

Eventos de la aplicación

Ahora que conocemos todos los detalles y la forma de trabajar desde dentro, vamos a ver lo que necesitamos hacer durante el ciclo de vida de una aplicación. El PhoneApplicactionService se enfoca en cuatro eventos primarios durante el modelo de ejecución de la aplicación que nos ayuda a administrar el estado:

*Launching – Este evento es alcanzado cuando una nueva instancia de la aplicación es creada por alguna acción del usuario como seleccionarla de la lista, seleccionar el Tile o cualquier otro medio, En este caso, comenzamos con un nuevo inicio y no con la continuación de cualquier aplicación pasada.

*Deactivated – Este evento es alcanzado cuando el usuario navega fuera de nuestra aplicación o un Chooser es lanzado. Esta es la mejor oportunidad para nosotros de guardar el estado de la aplicación en el diccionario de estado para su uso futuro al regresar a la aplicación. Si se regresa del estado dormido, esto no sería necesario, pero lo es absolutamente si se regresa desde Tombstoning y el evento es el único chance que tendremos de guardar el estado de la aplicación.

*Activated – Este evento es lanzado cuando la aplicación está regresando del segundo plano, de cualquier modo. Y adivina, una simple llamada a la API por medio de IsApplicationInstancePreserved  y sus argumentos nos dirán desde que modo nuestra aplicación ha regresado. Si la bandera es verdadera, nuestra aplicación viene desde el estado Dormant, y fue mantenida en la memoria. Así que no es necesaria ninguna acción y FAS lo hace todo. Si la bandera es falsa, estamos regresando desde el Tombstone y usaríamos el diccionario de estado para recuperar el estado de la aplicación.

* Closing – Este evento es lanzado cuando el usuario atraviesa por medio de las páginas, llega a la página principal y sale de ella. En este punto, la aplicación debió haber salido del primer plano y se habrá terminado a sí misma después de alcanzar un evento. No se preserva ningún estado de información al terminar y cualquier lanzamiento subsecuente de la aplicación resultará en una nueva instancia.

Como un tema común, las tareas intensivas con altos recursos deberían ser evitadas durante cualquiera de los eventos anteriores, dado que tenemos un lapso de tiempo limitado (diez segundos para ser exacto) para que el SO espere por nuestros métodos para finalizar. Para una mejor experiencia de usuario, algunas de las operaciones de mantenimiento deberán ser realizadas en hilos de segundo plano mientras la aplicación esté corriendo.

Si quieres que tenga sentido toda esta información. Solo dale un vistazo al diagrama general del modelo de ejecución para Windows Phone, mejor descrito en el artículo de MSDN:

Execution-Model

[Cortesía MSDN]

Aplicación de prueba

Hemos estado con mucha plática hasta ahora, ¿no es así? Vamos a ver algo de código. Vamos a crear una aplicación Windows Phone simple que resalte la administración de estados a través de todo el ciclo de vida de la aplicación. La aplicación entera y construida esta disponible para su descarga al final del artículo, solo asegúrate de que tienes el SDK de Windows Phone 7.1, y ¡Presiona F5!

Así que comencemos, Archivo > Nuevo y aceptamos la plantilla mas básica para una aplicación con una sola página XAML únicamente, siendo esta MainPage.xaml.cs. Vamos a abrir la página XAML y arrastrar algunos controles para nuestro uso. El resultado final debe ser algo como esto.

XAML-Page_thumb

Aquí está el objetivo, vamos a utilizar los controles para administrar los stados de varios tipos de información como se describe abajo.

*AppSetting – Este es un ejemplo de un nivel de aplicación que debe persistir a través de las instancias de la aplicación. El ejemplo más común podría ser el ajuste de un usuario para tu aplicación.

* App Transient Data – Este conjunto de controles simulará el nivel de información de la aplicación que es solo aplicable por instancia, pero puede ser utilizable en múltiples páginas XAML durante toda la aplicación. El mejor ejemplo sería alguna información de un servicio web que una aplicación busque cada vez que inicia.

* Page Transient Data – Este conjunto de controles  permanece para el control de página específico que probablemente no queramos perder si el usuario sale de nuestra aplicación y vuelve de regreso desde el segundo plano.

Vamos a manejar cada tipo de información de forma separada. Así vamos a comenzar con el archivo App.xaml.cs (el lugar para manejar información global de la aplicación). Vamos a agregar unas propiedades así como un poco de código en el Constructor.

public PhoneApplicationFrame RootFrame { get; private set; }

        public bool AjustesApp { get; set; }
        public string InfoApp { get; set; }

        public static new App Current
        {
            get { return Application.Current as App; }
        }

        public App()
        {
            UnhandledException += Application_UnhandledException;
            InitializeComponent();
            InitializePhoneApplication();
            InfoApp = string.Empty;

            if (System.Diagnostics.Debugger.IsAttached)
            {
                Application.Current.Host.Settings.EnableFrameRateCounter = true;
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }

            if (IsolatedStorageSettings.ApplicationSettings.Contains(“AppSetting”))
            {
                AjustesApp = (bool)IsolatedStorageSettings.ApplicationSettings["AppSetting"];
            }

        }

Después, vamos a agregar algo de código a los manejadores de eventos de la aplicación. Nota el uso de la bandera IsApplicationInstancePreserved para decidir si estamos viniendo de los estados Dormant o Tombstoning en el manejador de eventos Activated. Ahora, no tuve una buena razón para agregrar ningún código especial a los manejadores de Launching y Closing de la aplicación, pero sientete libre de hacerlo si tu aplicación necesita ese código. También, nota el uso del diccionario Stat del PhoneApplicationService:

private void Application_Activated(object sender, ActivatedEventArgs e)
        {
            if (e.IsApplicationInstancePreserved)
            {
                // Regresar desde Dormancy.
            }
            else
            {
                // Regresar desde Tombstone.
                if (PhoneApplicationService.Current.State.ContainsKey(“AppData”))
                {
                    InfoApp = PhoneApplicationService.Current.State["AppData"].ToString();
                }
            }
        }

        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            PhoneApplicationService.Current.State["AppData"] = InfoApp;
        }

Ahora, de vuelta a nuestro MainPage.xaml.cs, vamos a agregar los manejadores de eventos para el evento de cargando y el clic del botón para buscar algo de información (la cual creamos nosotros) así como el cambio de estado del CheckBox. Nota como mantenemos la información encontrada en nivel de la aplicación y también como guardamos inmediatamente los ajustes del usuario/aplicación en el almacenamiento aislado del teléfono.

private void chkAjusteAplicacion_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (IsolatedStorageSettings.ApplicationSettings.Contains(“AppSetting”))
            {
                IsolatedStorageSettings.ApplicationSettings.Remove(“AppSetting”);
            }

            if ((bool)this.chkAjusteAplicacion.IsChecked)
            {
                IsolatedStorageSettings.ApplicationSettings.Add(“AppSetting”, true);
            }
            else
            {
                IsolatedStorageSettings.ApplicationSettings.Add(“AppSetting”, false);
            }
        }

        private void btnBuscar_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            txtInfoApp.Text = “Esta es alguna información de ejemplo…”;
            App.Current.InfoApp = txtInfoApp.Text;
        }

        private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            chkAjustePagina.IsChecked = App.Current.AjustesApp;
        }

Ahora, vamos a agregar los importantes eventos para la navegación de páginas. Aquí es donde obtenemos control de como alimentar la información mientras la página XAML viene a primer plano y te mueves fuera de ella.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (App.Current.InfoApp != null && App.Current.InfoApp != string.Empty)
            {
                txtInfoApp.Text = App.Current.InfoApp;
            }

            if (PhoneApplicationService.Current.State.ContainsKey(“PageData”))
            {
                txtInfoPagina.Text = PhoneApplicationService.Current.State["PageData"].ToString();
            }
            if (PhoneApplicationService.Current.State.ContainsKey(“PageSetting”))
            {
                chkAjustePagina.IsChecked = (bool)PhoneApplicationService.Current.State["PageSetting"];
            }
        }

        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            if (PhoneApplicationService.Current.State.ContainsKey(“PageData”))
            {
                PhoneApplicationService.Current.State.Remove(“PageData”);
            }

            if (PhoneApplicationService.Current.State.ContainsKey(“PageSetting”))
            {
                PhoneApplicationService.Current.State.Remove(“PageSetting”);
            }

            PhoneApplicationService.Current.State["PageData"] = txtInfoApp.Text;
            PhoneApplicationService.Current.State["PageSetting"] = chkAjustePagina.IsChecked;
        }

¡Eso es todo! Hemos agregado el suficiente código de modo que los diferentes tipos de información sean administrados a través del ciclo de vida de la aplicación, cada una en una forma diferente y apropiada. Ahora dale una probada. Inicia la aplicación, has los cambios necesarios, ve a alguna otra aplicación y de regreso o salte y corre una instancia fresca de la aplicación. La información y el estado deberían ser preservadas como se espera. Una ejecución típica con los ajustes necesarios deberá verse así:

App-and-Page-State_thumb

Ahora, quizá notes una cosa, en ambos, en el emulador o en el teléfono que mientras navegamos por la aplicación, nos salimos y después regresamos en el runtime de Windows Phone Mango, es difícil predecir cuando la aplicación sea desechada. En la mayoría de los casos, si es desactivada, la aplicación simplemente queda en estado dormido y vuelve a la vida. Así que a menos que que configuremos a la aplicación para ir directo a Tombstoning, no hay una forma definitiva de probar esto.

¡No te preocupes! Hay un simple valor de depuración que forzará el tombstone en tu aplicación al momento en que sea desactivada. Así que incluso si la aplicación puede estar en estado dormido, este parámetro, mostrado abajo, la forzara a ir al Tombstone. Esto obviamente ayudará a nuestras pruebas.

En Resumen

Agregando puntos de interrupción a varios manejadores de eventos y viendo cuando se disparan durante el ciclo de vida de la aplicación, es una forma genial de entender el modelo de ejecución. Así que ¿Qué esperas? Ve y has uso completo de FAS y como alimentar a tu aplicación de forma correcta durante cualquier etapa de ella.

Resultado, usuarios felices y tu más feliz ¡Adios!

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana, Chris Koeing va a hablar acerca de otra genial herramienta disponible para nosotros en Visual Studio 2010, la herramienta de análisis de rendimiento de Silverlight. Nos vemos.

Categories: Tutoriales, WP7 Tags:

Día 22: App Connect

December 21st, 2011 No comments

Esta es una traducción de Day 22: App Connect, puedes encontrarlo aquí en su versión original en inglés.

dia22

¿Qué es App Connect?

Windows Phone Mango introduce una multitud de mejoras fantásticas al ya genial sistema operativo Windows Phone. Además de estas, hay un número de mejoras al motor de búsqueda de Bing en el teléfono. Mientas que muchos de esos elementos como búsqueda visual dirección paso a paso están hechos para los usuarios, Microsoft también introdujo unos cuantos elementos que permitan a los desarrolladores integrar aplicaciones en los resultados de búsquedas ya sea vía respuestas instantáneas, una forma de resaltar aplicaciones relevantes para búsquedas específicas, o vía un nuevo elemento en Mango llamado Quick Cards.

Quick Cards son elementos que aparecen en cuertas búsquedas que permiten a los usuarios encontrar mas acerca de cierto productos, ubicaciones o películas dentro de Bing. En la imagen de abajo se muestra un ejemplo de resultados de búsqueda que incluyen Quick Cards para muchos libros que coincidan con la búsqueda del usuario.

clip_image002

Al dar clic en alguno de esos elementos navegarás hacía la Quick Card del producto la cual te permite encontrar mas información de un producto centralizado en la localización como se muestra abajo.

clip_image0041

App Connect es otro nuevo elemento en Windows Phone Mango que permite a las aplicaciones ser enlistadas en las elementos de las Quick Cards que son relevantes para cuestiones de una búsqueda. Desde aquí, el usuario puede dar clic y lanzar la aplicación y tener la experiencia que viene de la Quick Card personalizada desde la cual el usuario llegó.

Es importante notar que hasta ahora solo los Estados Unidos soportan Quick Cards de productos y películas, pero también mencionar que paulatinamente ser irá extendiendo. Sin considerar esta limitación actual, también veremos el texto de resultados de las búsquedas localizadas.

Checa http://msdn.microsoft.com/en-us/library/hh202957%28v=VS.92%29.aspx#BKMK_AppConnect para una lista mas detallada y actualizada de los tipos de Quick Cards que están soportadas.

Similares a las Quick Cards, los desarrolladores pueden también hacer que sus aplicaciones estén al pendiente de los escenarios donde son ejecutadas como por Bing Instant Answers, otra mejora de Mango a la búsqueda de Bing. Bing Instant Answers permite a Bing resaltar ciertas aplicaciones que considere son relevantes para una búsqueda específica.

Para este artículo estaremos creando una aplicación que te permita rápidamente buscar un libro para un sitio de ventas en línea tomando ventaja de la integración de búsquedas de Quick Cards para libros, revistas y dando una experiencia personalizada si fue lanzada desde Bing Instant Answers.

Comenzar con la extensión de búsqueda

Ajustar tu aplicación para tomar ventaja de App Connect es relativamente fácil a pesar de que hay un número de pasos que necesitarás seguir para hacer funcionar las cosas.

Comenzaremos creando un nuevo proyecto de Windows Phone Application en la opción de Windows Phone 7.1.

Registrar extensiones de búsqueda

Para que Windows Phone sepa que tu aplicación soporta App Connect, necesitas agregar una entrada al archivo de manifiesto diciendo al teléfono que la aplicación soporte la extensión de búsqueda. Esto es importante y debería incluir los tipos de producto relevantes para tu aplicación.

Expande el nodo de propiedades del archivo de proyectos y ve a WMAppManifest.xml. Este es el manifiesto de la aplicación del teléfono para el Marketplace y define toda la información relevante de tu aplicación. Necesitarás agregar un nuevo nodo dentro del elemento App ilustrado en el siguiente archivo.

<Deployment xmlns=”http://schemas.microsoft.com/windowsphone/2009/deployment” AppPlatformVersion=”7.1″>
<App xmlns=”” ProductID=”{b8d10135-ffd2-48e0-852d-42a55e277b37}” Title=”Dia_22_AppConnect” RuntimeType=”Silverlight” Version=”1.0.0.0″ Genre=”apps.normal”  Author=”Dia_22_AppConnect author” Description=”Sample description” Publisher=”Dia_22_AppConnect”>
<IconPath IsRelative=”true” IsResource=”false”>ApplicationIcon.png</IconPath>
<Capabilities></Capabilities>
<Tasks>
<DefaultTask  Name =”_default” NavigationPage=”MainPage.xaml”/>
</Tasks>
<Tokens>
<PrimaryToken TokenID=”Dia_22_AppConnectToken” TaskName=”_default”>
<TemplateType5>
<BackgroundImageURI IsRelative=”true” IsResource=”false”>Background.png</BackgroundImageURI>
<Count>0</Count>
<Title>Dia_22_AppConnect</Title>
</TemplateType5>
</PrimaryToken>
</Tokens>
<Extensions>
<!– Extensión beta, solo para uso de pruebas y desarrollo –>
<Extension ExtensionName=”Productos” ConsumerID=”{5B04B775-356B-4AA0-AAF8-6491FFEA5661}” TaskID=”_default” ExtraFile=”Extensiones/Extras.xml” />
<!– Extensiones de producción, para ingrsar al Marketplace –>
<Extension ExtensionName=”Bing_Productos_Libros_y_Revistas” ConsumerID=”{5B04B775-356B-4AA0-AAF8-6491FFEA5661}” TaskID=”_default” ExtraFile=”Extensiones/Extras.xml” />
</Extensions>
</App>
</Deployment>

El aspecto importante de esto son los dos elementos de Extension. ExtensionName identifica con que tipo de extensión para integrar con las Quick Cards se usará. Visita http://msdn.microsoft.com/en-us/library/hh202958%28v=VS.92%29 para una lista completa de Quick Cards disponibles.

El emulador maneja el App Connect de forma diferente que en la versión final de Mango que se ejecuta en el teléfono. En el emulador todos los productos Quick Card tienen una categoría de “Productos” en lugar los ExtensionNames individuales mas específicos. Esto es para decir que si registramos nuestra aplicación para soportar libros y revistas usando “Bing_Productos_Libros_y_Revistas”, nuestra aplicación mostraría la Quick Card de un libro en el dispositivo pero no en el emulador y si registramos para solo soportar solo la categoría de “Productos”, la aplicación parecería trabajar bien en el emulador pero no trabajaría propiamente en dispositivos físicos. Debido a que vas a querer soportar ambos, la categoría “Productos” así como cualquier categoría que quisieras manejar definiendo múltiples elementos de Extensión.

Los otros campos en el elemento de Extensión son relativamente simples con los cuales trabajar: ConsumerID identifica la extensibilidad de búsqueda así como la extensión de elemento y no debería ser cambiada. IDTarea especifica la tarea que debería ser lanzada cuando la extensión sea activdada. ArchivoExtra le dice a la aplicación hacia donde mirar para información adicional necesaria para soportar la integración de búsqueda y debe apuntar a Extensiones/Extras.xml o App Connect no funcionará.

Configurar información adicional necesaria para el App Connect

Dado que nuestro proyecto no contiene el archivo XML al que hacemos referencia en las dos extensiones que registramos, deberemos crarlo. Da clic derecho en el proyecto en el explorador de soluciones y selecciona “Add –> New Folder”, renombralo como “Extensiones”, da clic derecho sobre la carpeta y selecciona “Add –> New Item”. Selecciona el archivo XML de la lista y nómbralo “Extras.xml”. El nombre y ruta del archivo debe ser exacto o las extensiones de búsqueda no funcionarán propiamente.

clip_image006

Ahora tienes el archivo Extras.xml en la carpeta. Desde aquí necesitaremos agregar un nodo ExtrasInfo al archivo XML que defina como se comportará la aplicación con las extensiones que hemos registrado.

<ExtrasInfo>
<AppTitle>
<default>Soporte Libro</default>

<en-EN>Book Helper</en-EN>
<fr-FR>Livre Helper</fr-FR>
<zh-CN>本书帮助器</zh-CN>
</AppTitle>

<Consumer ConsumerID=”{5B04B775-356B-4AA0-AAF8-6491FFEA5661}”>

<ExtensionInfo>
<Extensions>
<ExtensionName>Productos</ExtensionName>
<ExtensionName>Bing_Productos_Libros_y_Revistas</ExtensionName>
</Extensions>
<CaptionString>
<default>Search vendors for books and eBooks</default>

<en-EN>Búsqueda de libros y libros electrónicos de varios proveedores</en-EN>
<fr-FR>Recherche de livres et eBooks provenant de divers fournisseurs</fr-FR>
<zh-CN>搜索图书和电子图书来自不同供应商</zh-CN>
</CaptionString>
</ExtensionInfo>

</Consumer>
</ExtrasInfo>

El elemento AppTitle y sus hijos le dicen a Windows Phone como llamar a nuestra aplicación ( y le da algunas cadenas localizadas para diferentes idiomas). El nodo “default” dentro de este es usado si una cadena local no puede ser encontrada y debería representar el título de la aplicación en el lenguaje neutral de la aplicación. Los nodos adicionales pueden ser agregados con nombres que coincidan con el código del idioma para el cual sea la cadena local. Por ejemplo, es-ES en este ejemplo indica la cadena usada en ajustes de idioma español.

El nodo Consumer tiene un ConsumerID que coincide con el ConsumerID que registramos en el archivo WMAppManifest.xml. Dentro de este nodo esta un nodo llamado ExtensionInfo con un nodo de Extensiones que contienen elementos ExtensionName que definen las extensiones que dijimos que se podrían soportar.

El elemento CaptionString define el mensaje usado a un lado de la imagen de la extensión de búsqueda y es localizado de la misma forma que AppTitle. Un ejemplo de esta aplicación mostrando una extensión de búsqueda es el ejemplo de abajo.

clip_image008

Nota que el ícono de la aplicación es usado para esta imagen y el fondo podría ser claro u oscuro dependiendo del tema. Consecuentemente, la transparencia en los íconos de una aplicación no podrían ser utilizadas cuando la integración con App Connect se dé. Adicionalmente, el elemento pivote para AppConnect en las Quick Cards dice “extras” mientras que en un dispositivo Mango, este pivote esta etiquetado como “apps”.

Si necesitas especificar diferentes letras para diferentes tipos de productos, puedes hacerlo declarando múltiples elementos ExtensionName en un elemento ExtensionInfo y otros en otro, mientras que todos tus ExtensionNames que digas estén representados en un ExtensionInfo.

Ajustar el URI mapping

Cuando un usuario entra a la aplicación usando App Conect, el runtime intentará navegar a la URI /SearchExtras. Para soportar este punto de entrada necesitaremos ajustar algunos mapeos de URI para redireccionar el tráfico a la página apropiada. Para hacer esto, definiremos un recurso UriMapper en los recursos de la aplicación en App.xaml y agregando el siguiente recursos a Application.Resources:

<Application.Resources>
<nav:UriMapper x:Key=”UriMapper” xmlns:nav=”clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone”>
<nav:UriMapper.UriMappings>
<nav:UriMapping Uri=”/SearchExtras” MappedUri=”/MainPage.xaml” />
</nav:UriMapper.UriMappings>
</nav:UriMapper>
</Application.Resources>

Definir este recurso no es suficiente. Necesitamos decirle a la aplicación que encuentre y use este UriMapper para resolver solicitudes. Hacemos esto agregando la siguiente línea de código al constructor en App.xaml.cs:

RootFrame.UriMapper = Resources["UriMapper"] as UriMapper;

Esto dirigirá correctamente todo el tráfico entrante de App Connect para navegar en la MainPage una vez que tu aplicación inicie. Si quisieramos, podríamos especificar una página particular en la propiedad MappedUri que es específica para el App Connect, pero para los propósitos de este ejemplo, esto será suficiente.

Tomar ventaja de la integración con App Connect

Hasta ahora, si corres tu aplicación en el emulador y después vas a la búsqueda de Bing en el dispositivo usando la tecla de buscar, verías tu aplicación listada en el control Pivot “extras” para una Quick Card del producto –siempre y cuando esté hecha para dar soporte – mapeos de tipo de producto individual no funcionan para el emulado, pero si para un dispositivo real (y viceversa ).

Desafortunadamente, nustra aplicación no hace aún nada con la información proveniente por App Connect. Para arreglar esto, vamos a comenzar definiendo la interfaz del usuario. Ve a MainPage.xaml y reemplaza el Grid llamado LayoutRoot y todos sus hijos con el siguiente XAML.

<Grid Background=”Transparent”>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto” />
<RowDefinition Height=”*” />
</Grid.RowDefinitions>
<StackPanel Margin=”12,17,0,28″>
<TextBlock Text=”LA LIGA SILVERLIGHT” Style=”{StaticResource PhoneTextNormalStyle}” />
<TextBlock Text=”app connect” x:Name=”txtTitulo” TextWrapping=”Wrap” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}” />
</StackPanel>
<ScrollViewer Margin=”12,0,12,0″ Grid.Row=”1″>
<StackPanel>
<TextBlock x:Name=”txtTituloLibro” TextWrapping=”Wrap” Visibility=”Collapsed” Style=”{StaticResource PhoneTextLargeStyle}” Text=”Book title goes here” />
<TextBlock TextWrapping=”Wrap” x:Name=”txtSinBusqueda” Text=”Para usar este productos, utiliza las funciones de búsqueda para buscar un libro y después selecciona esta aplicación desde la sección de aplicaciones.”
Style=”{StaticResource PhoneTextNormalStyle}” />
<HyperlinkButton HorizontalContentAlignment=”Left” Foreground=”{StaticResource PhoneAccentBrush}”
Margin=”{StaticResource PhoneVerticalMargin}” Content=”Buscar en Amazon” Click=”ManejarBusquedaAmazon” />
<HyperlinkButton HorizontalContentAlignment=”Left” Foreground=”{StaticResource PhoneAccentBrush}”
Margin=”{StaticResource PhoneVerticalMargin}” Content=”Buscar en Barnes y Nobde” Click=”ManejarBusquedaBarnesAndNoble” />
</StackPanel>
</ScrollViewer>
</Grid>

Esto define una interfaz de usuario que será capaz de funcionar en cualquier aplicación independiente (en el caso del lanzamiento de una aplicación normal o servir como una página de detalles si la aplicación es lanzada usando App Connect. Preestablecidamente, la aplicación se verá como la siguiente imagen.

clip_image010

Manejar los parámetros de consulta

Obviamente, nos gustaría ser capaces de hacer algo especial si lanzamos la aplicación desde App Connect en una Quick Card que lanzó a la aplicación. Afortunadamente, cuando entramos a una página vía App Connect, el contexto de la navegación de la página contiene dos parámetros de consulta que nos pueden ayudar a identificar información básica en la Quick Card que lanzó la aplicación. La cadena de consulta ProductName contendrá el nombre del producto que esta asociadocon la Quick Card que els usuario acaba de ver y el argumento Categoría será el ExtensionName que esta asociado con esa Quick Card.

Es importante esperar para que la página se cargue antes de checar los parámetros de consulta dado que el NavigationContext no estará disponible hasta que la carga haya sido completada.

Dado que esta es información es muy básica, es aún útil para aplicaciones que necesiten pre poblar campos o controles con nombres de productos o para páginas que necesitan ser flexibles lo suficiente para manejar múltiples tipos de productos. Ten en mente que para propósitos de depuración Category será siempre “Productos2 en el emulador, pero tendrá los valores correctos cuando corramos la aplicación en un dispositivo.

Para nuestra aplicación de ejemplo, tendremos la página desplegando el nombre del producto, si llegamos a la aplicación por medio de App Connect, pero dejaremos el existente si es que tenemos un inicio ordinario. Debido a que el punto de entrada de la aplicación y los extras de búsqueda usan la misma página para nuestra demo, es importante checar la existencia de la cadena de consulta antes de usarlas.

Aquí está el archivo C# del MainPage modificado que incluye la lógica para pasar los parámetros de consulta y manejar los clics de los hyperlinks.

public partial class MainPage : PhoneApplicationPage
{
private string libro;

public MainPage()
{
InitializeComponent();
Loaded += EventoCargado;
}

private void EventoCargado(object sender, RoutedEventArgs e)
{
if (NavigationContext.QueryString.ContainsKey(“ProductName”))
{
libro = NavigationContext.QueryString["ProductName"];
txtTitulo.Text = “Detalles Libro”;
}
else if (NavigationContext.QueryString.ContainsKey(“bing_query”))
{
libro = NavigationContext.QueryString["bing_query"];
txtTitulo.Text = “Búsqueda seleccionada”;
}
else
{
libro = null;
}

if (!string.IsNullOrWhiteSpace(libro))
{
txtTitulo.Text = libro;
txtSinBusqueda.Visibility = Visibility.Collapsed;
txtTituloLibro.Visibility = Visibility.Visible;
}
else
{
txtSinBusqueda.Visibility = Visibility.Visible;
txtTituloLibro.Visibility = Visibility.Collapsed;
}
}

private void ManejarBusquedaBarnesAndNoble(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(libro))
{
IrA(“http://www.barnesandnoble.com/ebooks/index.asp”);
}
else
{
IrA(“http://productsearch.barnesandnoble.com/search/results.aspx?store=BOOK&keyword=\”” + libro.Replace(” “, “+”) + “\””);
}
}

private void ManejarBusquedaAmazon(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(libro))
{
IrA(“http://www.amazon.com/gp/aw/sb.html/sn=Books”);
}
else
{
IrA(“http://www.amazon.com/gp/aw/s/?k=” + libro.Replace(” “, “+”));
}
}

private static void IrA(string address)
{
var webTask = new Microsoft.Phone.Tasks.WebBrowserTask();
webTask.Uri = new Uri(address);
webTask.Show();
}
}

Ahora, cuando lancemos la aplicación por medio de App Connect vemos lo siguiente:

clip_image012

Soportar App Instant Answers

Otro elemento introducido en Windows Phone Mango es App Instant Answers. Este es un elemento automático de la búsqueda de Bing donde Bing decide lo relevantes que pueden ser para colocarlas en la cima de los resultados. No tienes que hacer nada para soportar el lanzamiento desde Instant Answers pero puedes tomar ventaja de la información pasada por esta funcionalidad si así lo quieres. Esta información es expuesta por medio de un parámetro de la cadena de consulta llamado “bing_query” y es accedido similarmente por los parámetros ProductName y Category.

Modificar nuestra aplicación de ejemplo para tomar ventaja de Instant Answres es extremadamente fácil como es muestra en la primera mitad del método EventoCargado

if (NavigationContext.QueryString.ContainsKey(“ProductName”))
{
libro = NavigationContext.QueryString["ProductName"];
txtTitulo.Text = “Detalles Libro”;
}
else if (NavigationContext.QueryString.ContainsKey(“bing_query”))
{
libro = NavigationContext.QueryString["bing_query"];
txtTitulo.Text = “Búsqueda seleccionada”;
}

Esta modificación permite a la aplicación obtener el título del libro desde el nombre de producto de la Quick Card si alguno esta presente o desde la consulta de Bing que generó el resultado de Instant Answers. La imagen de abajo muestra el entrar a la aplicación por medio de Instant Answers para la cadena de búsquda “Sphere by Michael Crichton”

clip_image014

Probar App Connect

Quizá te estés preguntando como probar Instant Answers o adjuntar un depurador al trabajar con las extensiones de búsqueda. Este es un punto válido dado que no hay una buena forma de influenciar los resultados de las búsquedas de Bing usando el emulado y cuando se trabaja con extensiones de búsqueda, el atributo Category no registra lo mismo que debería en el dispositivo. También puede convertir el tiempo consumido para navegar a Bing, ejecutar una búsqueda específica y después lanzar la aplicación usando App Connect. Afortunadamente, hay una forma fácil de simular el lanzamiento de tu aplicación ya sea por medio de las extensiones de búsqueda o por medio de Instant Answers.

Dado que podemos predecir los parámetros de la cadena de consulta que Quick Cards generará cuando entre a nuestra aplicación, es posible colocar manualmente estos valores en el punto de entrada de la aplicación para propósitos de prueba. Las aplicaciones Windows Phone almacenan la dirección de la página preestablecida dentro del archivo WMAppManifest.xml en el nodo de propiedades de nuestro proyecto. Abre este archivo y encuentra el elemento DefaultTask dentro de la colección Tasks.  Se debería ver como esto.

<DefaultTask Name =”_default” NavigationPage=”MainPage.xaml”/>

Este elemento le dice a la aplicación hacia donde navegar cuando la aplicación inicie y puede ser modificado para apuntar hacia el archivo que tu desees. Puede también ser modificado para simular el ingreso a la aplicación vía las extensiones de búsqueda o Instant Answers especificando los parámetros de la cadena de consulta. Por ejemplo, la siguiente entrada fue usada para probar Instant Answers en la sección de arriba.

<DefaultTask Name =”_default” NavigationPage=”MainPage.xaml?bing_query=Sphere by Michael Crichton”/>

Las modificaciones para simular un punto de entrada por la extensión de búsqueda para un producto similar son muy parecidas. Nota que dado que estamos especificando múltiples parámetros para la cadena de consulta, estamos usando &amp; Es importante como se ve en el siguiente fragmento.

<DefaultTask Name =”_default” NavigationPage=”MainPage.xaml?Category=Bing_Products_Books_and_Magazines&amp;ProductName=Sphere”/>

Por supuesto, una vez que hayas terminado de probar y estés listo para publicar la aplicación, asegúrate de remover cualquier parámetro de la cadena de consulta que hayas ingresado manualmente para que la aplicación funcione como se espera.

Quizá ocasionalmente caigas dentro de errores de publicación al hacer modificaciones al archivo WMAppManifest.xml e intentes lanzar la aplicación en el emulador. Si la publicación muestra el mensaje “Installation of the application failed. Run time error has occurred. Fix the Capabilities in WMAppManifest.xml file.” y tu sección de capacidades luce bien, solo reconstruye la aplicación y prueba de nuevo.

En resumen

Esto abarca la cobertura de App Connect e Instant Answers, dos formas sencillas y fáciles de utilizar que permiten a tu aplicación integrarse con puntos de extensibilidad en el motor de búsqueda mejorado de Bing para Windows Phone Mango.

Para descargar este ejemplo entero de la aplicación de Windows Phone usando los conceptos aquí mostrados, puedes hacerlo en el enlace siguiente.

Puedes descargar el código aquí.

Mañana, Samidip Basu esta de vuelta para discutir el modelo de ejecución en Windows Phone, incluyendo Fast App Switching, y como Tombstoning (el cual fue cubierto en el Día 14 de los 31 días d Windows Phone) ha cambiado ligeramente para acomodarse al nuevo sistema operativo 7.5. Nos vemos.

Categories: Tutoriales, WP7 Tags: