Compartir a través de


Windows Phone 7

Su primera aplicación para Windows Phone

Jesse Liberty

El truco para escribir la primera aplicación para Windows Phone es crear algo suficientemente interesante para que tenga sentido, pero que al mismo tiempo sea lo suficientemente sencillo para poder avanzar realmente. Con es te fin lo guiaré a través de la creación de una utilidad sencilla que uso todos los días: NoteToMe. La idea es que puede escribir un mensaje y enviárselo a usted mismo; basta con presionar un solo botón, como puede ver en la Figura 1.

The NoteToMe InterfaceFigura 1 La interfaz de NoteToMe

En este artículo tocaré superficialmente varios temas, cada uno de los cuales trataré en los artículos siguiente. Algunos de los temas son:

  • Crear el diseño de la aplicación
  • Almacenar y recuperar datos del almacenamiento aislado
  • Eventos y control de eventos
  • Crear y ejecutar tareas (iniciadores y selectores)

Antes de comenzar, deberá descargar las herramientas de http://xbox.create.msdn.com. Si ya desbloqueó su teléfono pero no lo actualizó a Windows Phone 7.5 (“Mango”), ahora es el momento de hacerlo; Mango tiene cientos de características nuevas para el sistema operativo Windows Phone.

Para comenzar

Al igual que muchos otros desarrolladores de Windows Phone, he llegado a la conclusión que la mejor herramienta para crear aplicaciones para Windows Phone es una combinación de Visual Studio (para el código) y Expression Blend (para todo lo demás). Por lo tanto, comenzaremos por abrir Expression Blend y crearemos una nueva aplicación llamada NoteToMe, basada en Windows Phone SDK 7.1.

Comencemos por cambiar el título de la aplicación. Haga clic en el título y ubique la propiedad Text para ese control en la ventana Properties. Las instrucciones para el diseño de Metro (las instrucciones para el diseño de las aplicaciones en Windows Phone) exigen que el título esté en letras mayúsculas, así que cambie el título a NOTE TO ME.

Haga clic en el título de la página y presione Delete para eliminarlo.

Para crear el diseño necesitará una fila pequeña en la parte superior de la página. Haga clic en el margen para que aparezca una guía que sirve para ubicar visualmente la fila, tal como puede observar en la Figura 2.

Placing the Top Row of the LayoutFigura 2 Ubicación de la fila superior del diseño

Por supuesto, puede establecer el tamaño de la fila en forma manual directamente en el archivo XAML:

<Grid.RowDefinitions>
  <RowDefinition Height="1*"/>
  <RowDefinition Height="9*"/>
</Grid.RowDefinitions>

El asterisco detrás del valor indica el uso de tamaños relativos, en este caso 1:9. Es decir, el tamaño de la primera fila será la novena parte de la segunda fila. 

Adición de tres controles a StackPanel

La fila superior contiene tres controles, lado a lado:

  • Un TextBlock que actúa como etiqueta.
  • Un TextBlock con la dirección de correo electrónico.
  • Un Button para enviar el mensaje.

Puede observar el diseño en la Figura 3.

Three Controls in the Top Row
Figura 3 Tres controles en la fila superior

No se pueden colocar tres controles en una misma columna de una fila sin ubicarlos dentro de algún tipo de contenedor que los organice. Usaré un StackPanel y estableceré su orientación en horizontal; los StackPanel se apilan uno encima de otro o uno al lado del otro.

Para crear un StackPanel, haga clic en la flecha blanca diminuta a un lado del control Layout en la barra de herramientas, tal como aparece en la Figura 4.

Adding a StackPanel
Figura 4 Adición de un StackPanel

Haga clic en el StackPanel para seleccionar el control. Ahora arrastre un StackPanel dentro de la fila y establezca su alineación vertical y horizontal en stretch y sus márgenes en cero en la ventana Layout, tal como puede observar en la Figura 5.

Placing the StackPanel
Figure 5 Ubicación del StackPanel

Agregue el TextBlock, establezca el tamaño de la fuente en 32, y el texto en To. Ahora arrastre un TextBox en el StackPanel. (Fíjese en la importante pero sutil diferencia entre un TextBlock, para mostrar texto, y un TextBox, para escribir texto.) Establezca el nombre de este TextBox en Address. Finalmente, agregue un botón al StackPanel, póngale el nombre Send y establezca su contenido en Send.

Esto genera la configuración XAML que vemos en la Figura 6.

Figure 6 Diseño del StackPanel con XAML

<StackPanel
  Margin="0"
  Orientation="Horizontal">
  <TextBlock
    Margin="0,8"
    TextWrapping="Wrap"
    Text="To"
    Width="42"
    HorizontalAlignment="Left"
    VerticalAlignment="Center"
    FontSize="32" />
  <TextBox
    x:Name="Address"
    Margin="0,0,0,-7"
    TextWrapping="Wrap"
    Text="foo@bar.com"
    Width="293" />
  <Button
    x:Name="Send"
    Content="Send"
    Margin="0,4,0,0"
    Width="124"
    Click="Send_Click" />
</StackPanel>

Observe que el botón Send tiene una propiedad Click=“Send_Click”. Para crear esto, debe hacer clic en el botón, luego en la ventana Properties, luego haga clic en el botón Events, tal como puede ver en la Figura 7.

The Events Button
Figura 7 El botón Events

Esto abre todos los eventos del botón. Ubique el evento click y haga doble clic. El botón se actualiza con el evento, y aparecerá el editor de código (según la configuración de Blend, puede ser en Blend o en Visual Studio) para ese controlador de eventos. Por ahora, puede dejar este controlador tal como está:

private void Send_Click( object sender, RoutedEventArgs e )
{
}

Adición del control para el mensaje

Haga clic en el control TextBox en la barra de herramientas y luego agrande un TextBox hasta que ocupe la mitad de la página restante (dejamos la otra mitad para el teclado que aparecerá cuando haya que escribir algo en el TextBox). Establezca HorizontalAlignment en Stretch, VerticalAlignment en Top y los márgenes en 0. Establezca Width en Automatic y el alto en 244. Puede hacer todo esto al ojo cuando cambia el tamaño de TextBox o puede dibujar el TextBox aproximadamente a mano y establecer las propiedades en la ventana Properties, tal como aparece en la Figura 8.

Adding the TextBox
Figura 8 Adición del TextBox

Escritura del código

Ahora que los controles ya se encuentran en su lugar, está listo para trabajar en la lógica del programa. Debiera ver una pestaña llamada Projects en la esquina superior izquierda. Después de guardar todos los cambios, haga clic en la pestaña Projects, luego haga clic con el botón secundario en MainPage.xaml.cs y seleccione Edit In Visual Studio, tal como se observa en la Figura 9.

Getting Ready to Write the Code
Figura 9 Preparación para escribir el código

Especificación

Mi especificación (autoimpuesta) dice que el usuario no tiene que rellenar necesariamente el campo To cada vez que usa el programa, ya que este campo se rellena automáticamente con el contenido que tenía la última vez que se usó.

Además, al hacer clic en Send, se debiera preparar un nuevo mensaje de correo electrónico para el programa de correo electrónico, con todos los campos rellenados previamente; así que basta con que presione Send u opcionalmente edite el mensaje y luego presione Send.

Uso del almacenamiento aislado

Para conservar el contenido del campo To cada vez que se usa la aplicación, tenemos que almacenar el contenido en alguna parte en el teléfono. Para esto sirve el Almacenamiento aislado: para persisitir datos cuando la aplicación está cerrada. Como dice su nombre, el Almacenamiento aislado permite que la aplicación almacene los datos en forma aislada y protegida de los datos de otras aplicaciones. El uso del Almacenamiento aislado es bastante sencillo.

Primero debe agregar la instrucción using:

using System.IO.IsolatedStorage;

Declare una variable miembro del tipo IsolatedStorageSettings y una cadena constante que actúa como clave en el diccionario del Almacenamiento aislado para poder almacenar y recuperar la dirección de correo electrónico:

private IsolatedStorageSettings _isoSettings;
const string IsoKey = "EmailAddress";
Initialize the _isoSettings member in the constructor:
 _isoSettings = IsolatedStorageSettings.ApplicationSettings;

Almacenar y recuperar la dirección de correo electrónico

Las dos tareas relacionadas con el Almacenamiento aislado son almacenar la cadena y recuperarla. El mejor momento para almacenarla es al abandonar la página. Al abandonar cualquier página en Windows Phone se llama el método OnNavigatedFrom. Podemos reemplazarlo y una buena razón para hacerlo es almacenar los datos en el Almacenamiento aislado, del siguiente modo:

protected override void OnNavigatedFrom(
  System.Windows.Navigation.NavigationEventArgs e )
{
  _isoSettings[IsoKey] = Address.Text;
  base.OnNavigatedFrom( e );
}

Ahora la dirección de correo electrónico está almacenada en el diccionario _isoSettings con la clave IsoKey. Al volver a la página podemos restaurar la configuración. Para esto, llamo el método auxiliar privado RestoreEmailAddress dentro del constructor:

private void RestoreEmailAddress()
  {
    if (_isoSettings.Contains( IsoKey ))
      Address.Text = _isoSettings[IsoKey].ToString();
  }

Preste atención a que compruebo si existe la clave en el Almacenamiento aislado antes de intentar restaurarla; esto previene una excepción KeyNotFound la primera vez que se ejecuta el programa. Recuerde que la primera vez, aún no hemos almacenado nada en el Almacenamiento aislado.

La primera vez que se inicia el programa, no hay nada en el campo Address. Una vez que el usuario escribe una dirección de correo electrónico en el campo Address, esta dirección se almacena en el Almacenamiento aislado y se restaura la siguiente vez que se ejecuta el programa. Si el usuario cambia la dirección, al restaurar la aplicación se mostrará la nueva dirección.

Tareas

Windows Phone 7.5 cuenta con varias tareas para interactuar con las aplicaciones integradas en el teléfono (correo electrónico, lista de contactos, cámara, y así sucesivamente). Existen dos tipos de tareas: iniciadores y selectores. Los selectores se usan para seleccionar información y devolverla al programa (para obtener una dirección de correo electrónico de la lista de contactos, por ejemplo). Los iniciadores se usan para iniciar un programa que no devuelve datos.

En este caso, como ya tenemos todo que necesitamos para enviar el mensaje, podemos llamar el Launcher del correo electrónico y proporcionar los campos necesarios. Al llamar el método Show del iniciador para el correo electrónico se inicia la aplicación de correo electrónico con sus datos, pero no recibiremos de vuelta ningún tipo de datos (lo que está bien, ya que no los necesitamos).

Una vez que se envió el mensaje, vuelve a aparecer el programa para que podamos enviar otro mensaje, si así lo deseamos.

Todo el trabajo para crear el Launcher se encuentra encapsulado dentro del controlador del evento clic del botón Send. Comencemos por crear una instancia de EmailComposeTask (el Launcher). Rellene los campos obligatorios y llame Show. Eso es todo lo que tiene que hacer:

private void Send_Click( object sender, RoutedEventArgs e )
{
  EmailComposeTask emailComposeTask = new EmailComposeTask();
  emailComposeTask.Subject = "Send To Me";
  emailComposeTask.To = Address.Text;
  emailComposeTask.Body = Message.Text;
  Message.Text = String.Empty;
  emailComposeTask.Show();
}

Cuando llame Show, el asunto, la dirección y el cuerpo del mensaje se pasan a la aplicación de correo electrónico. Si tiene más de una aplicación de correo electrónico, se le pide que responda cuál desea usar. Se crea un mensaje de correo electrónico correctamente consignado y formateado, listo para enviarlo.

Ciclo de vida de la aplicación

Si se pudiera confiar en que los usuarios jamás van a interrumpir el uso de la aplicación hasta enviar el mensaje, ya estaríamos listos. En la vida real, sin embargo, los usuarios se detienen mientras están redactando un mensaje para lanzar una aplicación diferente. Cuando regresan, no estarán contentos si desaparece todo el esfuerzo invertido.

Para saber como protegernos contra esto, tenemos que entender un poco del ciclo de vida de las aplicaciones y saber cómo conservar el estado, y permitir al mismo tiempo una de las características más poderosas de Mango: la Conmutación rápida de aplicaciones.

Al lanzar la aplicación (digamos del menú Inicio), se activa el evento Application Launching. Una vez que se inicia la aplicación y cada vez que el usuario navega a la página, se llama el método OnNavigatedTo después del cual la página se encontrará en el estado Running. Si el usuario inicia una aplicación nueva, nuestra aplicación recibe el evento Application Deactivated y se pone en estado inactivo. Si al teléfono se le acaba la memoria, la aplicación se puede extinguir.

La aplicación se puede restaurar desde el estado extinto y el inactivo. Lo que nos interesa ahora es lo que ocurre al restaurarla.

Si la aplicación está inactiva, no solo no tenemos que hacer absolutamente nada cuando se restaura, sino que además no queremos hacer nada; como cuando la aplicación estaba inactiva se conserva el estado, está lista para seguir adelante.

Pero si la aplicación estaba extinta, entonces vamos a querer restaurar el estado de la página cuando vuelve nuestra aplicación, para que el usuario tenga la impresión que la aplicación se estaba ejecutando (o al menos inactiva) mientras estaba desactivada.

Por lo tanto nos enfrentamos a dos tareas:

  1. Guardar el estado cuando se llama el método OnNavigatedFrom de la página.
  2. Restaurar posiblemente el estado cuando se llama el método OnNavigatedTo de la página; debemos restaurarlo si la aplicación estaba extinta, pero no si estaba inactiva.

Guardar el estado cuando desaparece la página

Como cuando la página recibe el método OnNavigatedFrom no podemos saber cuál será el estado al restaurarla, tenemos que almacenar el estado por si acaso lo necesitamos más adelante. Esto es muy fácil: podemos usar un diccionario State que tiene una sintaxis muy parecida al diccionario del Almacenamiento aislado, aunque debemos recordar que el diccionario de estado no se almacena en forma permanente y de hecho se destruye al salir del programa o cuando se apaga el teléfono.

Comencemos por crear una cadena constante StateKey, que usaremos como clave en el diccionario State:

const string StateKey = "MessageState";

En el método OnNavigatedFrom almacenaremos el estado (en este caso, el contenido de MessageBox) en el diccionario State:

protected override void OnNavigatedFrom(
  System.Windows.Navigation.NavigationEventArgs e )
{
  _isoSettings[IsoKey] = Address.Text;
  State[StateKey] = Message.Text;
  base.OnNavigatedFrom( e );
}

Restauración del estado al crear la página

Cuando se llama el método OnNavigatedTo no queremos tomar medidas para restaurar State si la aplicación estaba inactiva, pero sí queremos actuar si estaba extinta.

Para distinguir entre el estado inactivo y el extinto podemos establecer una marca en falso y luego establecerla en verdadero en el constructor. Si la aplicación estaba inactiva no se llamará el constructor; si estaba extinta se llamará (ya que será la primera vez que se construya), de esta forma:

bool isNew = false;
  public MainPage()
  {
    InitializeComponent();
    isNew = true;

Podemos comprobar esa marca en OnNavigatedTo:

protected override void OnNavigatedTo(
  System.Windows.Navigation.NavigationEventArgs e )
{
  if (isNew)
  {
    if (State.ContainsKey( StateKey ))
    {
      Message.Text = State[StateKey].ToString();
    }
  }
  isNew = false;
  base.OnNavigatedTo( e );
}

Esta prueba nos permite ahorrar el tiempo que de lo contrario tendríamos que gastar en la restauración del valor del diccionario State. Para probarlo, puede ejecutar el programa primero en forma normal (en este caso cuando cambie a otra aplicación el programa se inactivará) y luego forzar que el programa se extinga. Para esto, puede hacer clic con el botón secundario en el proyecto, elija Propiedades, luego elija la pestaña Depurar y al depurar active la casilla Extinguir al desactivar.

Cuando ejecute el programa con este valor verá una pausa marcada cuando vuelva a la página, ya que se debe restaurar el estado.

Resumen final

En este artículo corto le mostré cómo escribir su primera aplicación no trivial para Windows Phone. Comencé por crear la aplicación en Expression Blend, donde creé una fila y un StackPanel para disponer los controles.

Luego pasé a Visual Studio para escribir la lógica del controlador de los eventos de los botones y usé el Almacenamiento aislado para persistir la dirección de correo electrónico. Usé la memoria State para garantizar que la aplicación se reinicie correctamente después de extinguirse.

Tal como mencioné, cada uno de estos temas da para mucho más, y los trataré en profundidad en los siguientes artículos.

Jesse Liberty es un evangelizador experto en la comunidad de desarrollo del equipo de Windows Phone. Es presentador del popular podcast Yet Another Podcast (jesseliberty.com/podcast), y su blog (jesseliberty.com/) es de lectura obligatoria. Liberty es autor de varios éxitos de ventas, incluidos los libros “Programming Reactive Extensions and LINQ” (Apress, 2011) y “Migrating to Windows Phone”, (Apress, 2011). Puede seguirlo por Twitter en twitter.com/JesseLiberty.

Gracias a los siguientes expertos técnicos por su ayuda en la revisión de este artículo: Drew Batchelor y Cheryl Simmons