Archive

Archive for the ‘Windows 8’ Category

31 días de Windows 8 | Día 16: Menú contextual

April 21st, 2013 1 comment

Este artículo es una traducción de “Día 16: Menú contextual” de Jeff Blakenburg. Puedes encontrar aquí la versión en inglés.

Hoy nuestro foco es en menús contextuales. Estos son aquellos pequeños comandos que se muestran ocasionalmente en tu aplicación cuando das un clic derecho o algo similar. Microsoft ofrece una guía muy especial en cuanto al uso de menús contextuales y cuando usar un control de AppBar en su lugar y seguiremos estas reglas en este artículo.

¿Qué es un menú contextual?

Si has usado Windows 8, probablemente los hayas encontrado. Comúnmente ellos se muestran al momento de dar clic derecho en algo que no puedas seleccionar o texto con el que quieras interactuar. Aquí hay un ejemplo de menú contextual:

An image of the context menu for text shown over editable text while there is no text in the clipboard to paste.

(imagen de: http://msdn.microsoft.com/library/windows/apps/Hh465308)

Podrías también lanzar un menú contextual desde un elemento en tu página que no sea seleccionable como esta imagen en mi aplicación de ejemplo:

16-XAML-ContextMenuExample

Dar clic derecho en la imagen lanza el menú contextual a la derecha. (Te mostraré como hacer que esto suceda a continuación). Cada uno de los comandos tendrán una función asignada a ella, el cual es ejecutado cuando el elemento sea presionado.

Determinando la ubicación de un elemento.

Quizá hayas notado que los menús contextuales aparecen adyacentes directamente al elemento que ha sido seleccionado. Esto no sucede por magia. De hecho deberemos determinar la posición del elemento seleccionado por nosotros mismos (así como su tamaño) y pasarlo a nuestro control menú cuando lo creamos en forma de un objeto de Rectángulo. Aquí esta el método que he creado para determinar su ubicación.

private Rect ObtenerRect(object sender)
{
FrameworkElement elemento = sender as FrameworkElement;
GeneralTransform transformacionElemento = elemento.TransformToVisual(null);
Point point = transformacionElemento.TransformPoint(new Point());
return new Rect(point, new Size(elemento.ActualWidth, elemento.ActualHeight));
}

Como puedes ver, seré capaz de para mi “sender” en este método y regresar un objeto Rectángulo con un punto (la ubicación de la esquina superior derecha de nuestro elemento) y tamaño (las dimensiones de nuestro objeto llamado).

Creando un menú contextual

Una vez que ya tengo el método ObtenerRect() en su lugar creando un menú contextual cerca de nuestros controles es simple. En este ejemplo, he agregado un evento Right Tapped a mi imagen el cual llama a este método.

private async void Element_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
PopupMenu menuContextual = new PopupMenu();
menuContextual.Commands.Add(new UICommand("La liga silverlight", (command) => { ((Grid)Logo.Parent).Background = new SolidColorBrush(Colors.Red); }));
await menuContextual.ShowForSelectionAsync(ObtenerRect(sender), Placement.Right);
}

Como puedes ver arriba, esto simplemente crea un nuevo control de tipo PopupMenu, agrega un comando a el (con el código de ejecución especificado en la expresión lambda) y llama al método ShowForSelectionAsync() para mostrarlo. Este método toma dos parámetros.

* El primero es el valor de Rectángulo que estamos obteniendo de nuestro método ObtenerRect(). Pasa el sender y obtiene el rectángulo apropiado de regreso.

* El segundo es la ubicación del menú contextual. En mi ejemplo, coloqué Placement.Right como mi valor. Tienes cuatro opciones pero no pierdas tiempo en esto. La guía de Microsoft en menús contextuales es que “aparezcan sobre el objeto sobre el que están actuando a menos que se interponga sobre otros elementos de la interfaz en cuyo caso se debe colocar a un lado o por debajo del objeto”. Mantén la experiencia en Windows 8 consistente para tus usuarios a menos de que tengas una buena razón para hacerlo de otra manera.

Ejecutar este código, como se muestra arriba, resultará en un menú que lucirá como esto:

image

Y cuando yo ejecute esta opción, el fondo de la página se volverá rojo. Como esto.

image

Así que así es como mostramos un menú contextual. Pero ¿cuántos comandos podemos tener a la vez? La respuesta es SEIS. Agregar más de 6 elementos a tu menú PopupMenu resultará en un error cuando trates de crearlo. Lo mostré antes pero aquí está un ejemplo de un menú de cinco elementos.

image

Finalmente, también tienes la opción de crear un UICommandSeparator() el cual es simplemente una línea horizontal en lugar de un comando. Los separadores tomarán lugar en uno de tus seis espacios disponibles sin embargo; así que ten esto en cuenta cuando lo uses, esto lucirá así.

image

Para hacer esto, tu sentencia de creación del comando debería lucir como esto:

menuContextual.Commands.Add(new UICommand("31 Días de Windows 8", (command) => { ((Grid)Logo.Parent).Background = new SolidColorBrush(Colors.Orange); }));
menuContextual.Commands.Add(new UICommandSeparator());

¡Esto es todo! Ahora deberías ser capaz de agregar menús contextuales a tus aplicaciones cuando las AppBars y otros elementos no tienen sentido. Pero ¿qué hay acerca interactuar con algo de texto en una caja de texto?

Lanzar un menú contextual desde una caja de texto

Actualmente, cerca de todo en este proceso es el mismo, excepto por las matemáticas de donde surge la la caja contextual. Inicialmente al comenzar a resolver este problema, estaba esperando agregarla en un menú contextual que ya apareciera cuando des clic derecho en el texto.

image

Mientras aparece no puede. Así que para nuestro ejemplo, vamos a decir que queremos mantener todas esas opciones, pero también agregar algunas nuevas. Para hacerlo, primero necesitamos sobre escribir el menú contextual creando un manejador de eventos para cancelar el pre establecido y recrear toda su funcionalidad.

Para hacer esto, creamos un manejador de eventos como el siguiente.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
txtLipsum.ContextMenuOpening += txtLipsum_ContextMenuOpening;
}

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
txtLipsum.ContextMenuOpening -= txtLipsum_ContextMenuOpening;
}

También cree una sentencia para retirar el manejador de eventos cuando deje la página.

En el método que este manejador de eventos llama, cancelaremos la llamada inicial con Handled = true, y después crear nuestro propio menú contextual que aún haga algunas de las llamadas apropiadas al portapapeles. Solo vamos a cubrir esta parte brevemente en este artículo pero consumiremos el artículo entero de mañana para las diferentes formas de usar esta gran herramienta.

En suma, encontrar el lugar adecuado para mostrar un menú contextual dentro de un TextBox es diferente a solo determinar la posición de un control en la página. Aquí está mi método ObtenerRectanguloTexto().

private Rect ObtenerRectanguloTexto(TextBox cajaTexto)
{
Rect contenedorDatos = cajaTexto.GetRectFromCharacterIndex(cajaTexto.SelectionStart, false);

GeneralTransform transform = cajaTexto.TransformToVisual(null);
Point punto = transform.TransformPoint(new Point());
punto.X = punto.X + contenedorDatos.X;
punto.Y = punto.Y + contenedorDatos.Y;

return new Rect(punto, new Size(contenedorDatos.Width, contenedorDatos.Height));
}

Y aquí esta el método para crear nuestro menú Popup (notarás que he usado un método secundario para determinar que comando es presionado que no use expresiones lambdas en esta ocasión. Es más fácil para lectura pero deberías también notar que el método es mucho más largo).

async void txtLipsum_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
e.Handled = true;
TextBox textoResaltado = (TextBox)sender;

PopupMenu menuContextual = new PopupMenu();
menuContextual.Commands.Add(new UICommand("Cortar", null, 0));
menuContextual.Commands.Add(new UICommand("Copiar", null, 1));
menuContextual.Commands.Add(new UICommand("Pegar", null, 2));
menuContextual.Commands.Add(new UICommand("Seleccionar todo", null, 3));
menuContextual.Commands.Add(new UICommandSeparator());
menuContextual.Commands.Add(new UICommand("Borrar", null, 4));

var comandoElegido = await menuContextual.ShowForSelectionAsync(ObtenerRectanguloTexto(textoResaltado));

if (comandoElegido != null)
{
String texto;
DataPackage paqueteDatos;

switch ((int)comandoElegido.Id)
{
case 0: //Cortar
texto = textoResaltado.SelectedText;
textoResaltado.SelectedText = "";
paqueteDatos = new DataPackage();
paqueteDatos.SetText(texto);
Clipboard.SetContent(paqueteDatos);
break;
case 1: //Copiar
texto = textoResaltado.SelectedText;
paqueteDatos = new DataPackage();
paqueteDatos.SetText(texto);
Clipboard.SetContent(paqueteDatos);
break;
case 2: //Pegar
texto = await Clipboard.GetContent().GetTextAsync();
textoResaltado.SelectedText = texto;
break;
case 3: //Seleccionar todo
textoResaltado.SelectAll();
break;
case 4: //Borrar
textoResaltado.SelectedText = "";
break;
}
}
}

Si estás siguiendo tu propio proyecto, deberías ahora ser capaz de resaltar algo de texto en tu caja de texto y obtener un menú similar al de la imagen de arriba.

En resumen

Hoy vimos el arte de crear menús contextuales para nuestros usuarios. Hay una manera excelente de proveer interacciones con elementos que no sean seleccionables o para comandos que tengan más sentido estando directamente adyacentes al elemento con el que se está interactuando.

Si quisieras ver el código de ejemplo completo para este artículo, presiona sobre el ícono de abajo.

 

 

Mañana, como prometí, nos aventuraremos en la funcionalidad del portapepeles disponible para nosotros en el desarrollo de Windows 8. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 15: El teclado en pantalla

March 29th, 2013 2 comments

Este artículo es una traducción del día #15 en la serie 31 días de Windows 8 de Jeff Blakenburg.

Hoy vamos a dar un vistazo al teclado en pantalla de Windows 8. Microsoft no parece hacer una distinción de nombres entre el teclado que aparece cuando haces tap con tu dedo en un control TextBox y el que encuentras en el Centro de Accesibilidad. Vamos a enfocarnos hoy en el teclado que se ve como esto:

15-XAML-NormalKeyboard

Por otro lado, el teclado de Accesibilidad, es una herramienta diseñada para hacer más fácil el uso de la computadora a quienes no pudieran usar el teclado de ninguna forma. Lo puedes encontrar abriendo el centro de Accesibilidad en tu maquina…

15-XAML-EaseOfAccessCenter

Y haciendo click en la opción de “Iniciar Teclado en Pantalla” vas a descubrir un teclado que se ve como este:

15-XAML-EaseOfAccessKeyboard

El enfoque principal de este teclado es permitir al usuario usar Windows completamente sin tener un teclado conectado a su computadora. No es personalizable, y no responde a ningún código que escribamos en este artículo. El teclado es también una de las pocas ventana que pueden ser puestas sobre la pantalla de Inicio. Míralo aquí:

15-XAML-OnScreenKeyboardStartScreen

OK, así hemos usado los primeros párrafos de este artículo hablando acerca de un teclado que NO es el objetivo de este artículo. ¿Porque? Hay dos razones:

  1. Si estas usando dispositivos no touch mientras trabajas con este artículo (o en tu propia app y quieres usar las características del teclado regular touch), te encontraras con que los clicks del mouse no lanzan el teclado touch en tu máquina. Así que buscaras en la web una solución para hacer que se muestren.
  2. Mientras buscas por la web más información sobre manipular el teclado en pantalla en Windows 8, vas a encontrar varios artículos sobre el de la versión de Accesibilidad, que es el que no necesitas. Si encuentras un artículo apropiado sobre como lanzar el teclado touch, probablemente sea este, porque no pude hallar una forma de hacerlo funcionar.

La primera razón de esto es porque este es uno de las pocas veces que Windows 8 hace distinción entre un click de mouse y un tap de dedo. Si das click en un TExtBox, Windows 8 asume que estas usando un teclado real, incluso si estas usando una máquina habilitada para touch. Un tap de dedo, sin embargo, mostrara el teclado que vamos a usar hoy.

Para ahorrarte algo de frustración, al desarrollar tu aplicación que tomara ventaja de el teclado en pantalla, usa el simulador si no estas trabajando en una maquina touch. Te permite simular “taps” con tu mouse. Aquí es donde lo puedes ver:

15-XAML-SimulatorTapButton

OK, ahora que hemos hecho a un lado todo eso, iniciemos de una vez este artículo.

 

Usando el teclado en pantalla

Primero, demos un vistazo a los estados por defecto del teclado en pantalla que el usuario puede navegar en cualquier momento cuando la pantalla está abierta. Hemos visto ya la vista QWERTY standard:

15-XAML-NormalKeyboard

Pero hay muchas más. Cuando construimos una aplicación, nuestro primer enfoque, mas que cualquier otro, debe ser el hacer que las tareas que el usuario necesita hacer sean lo más fácil de cumplir que se pueda. (Eso ESTÁ en tus prioridades, correcto?) En ese sentido, el teclado en pantalla puede ser manipulado para que eso sea posible. Hay una propiedad que puede establecerse en los controles TextBox llamada InputScrope que nos permite mostrar el teclado apropiado para la tarea a realizar. Si un InputScope no se especifica, el teclado normal se mostrará. Aquí está como luce el código:

<TextBox InputScope="EmailSmtpAddress" />

 

Vas a encontrar, mienstra empiezas a jugar con el InputScope, que hay de hecho 18 diferentes valores de InputScope que pueden ser usados (pero para usuarios Anglo-parlantes, hay de hecho solo tres teclados diferentes por ahora). Estos son (en orden alfabético):

  • AlphanumericFullWidth
  • AlphaNumericHalfWidth
  • ChineseFullWidth
  • ChineseHalfWidth
  • Default
  • EmailSmtpAddress
  • HangulFullWidth
  • HangulHalfWidth
  • Hanja
  • Hiragana
  • KatakanaFullWidth
  • KatakanaHalfWidth
  • NativeScript
  • Number
  • NumberFullWidth
  • Search
  • TelephoneNumber
  • Url

Los únicos valores de ámbito de entrada que responden a computadoras con el lenguaje Inglés de pantalla son: Default, EmailSmtpAddress, Number, Search, TelephoneNumber, y Url. Aquí está como se ven:

EmailSmtpAddress (agrega el botón “@” y “.com”)

15-XAML-EmailKeyboard

Url (agrega botones “/” y “.com”, barra de espacio más pequeña, tecla Go)

15-XAML-URL

Number y TelephoneNumber (muestra el teclado numérico)

15-XAML-Number

Búsqueda (lo mismo que el teclado por defecto, pero la tecla Enter remplazada por Search o Búsqueda)

15-XAML-Search

El resto de los valores InputScope están generalmente enfocados a los lenguajes Asiatico Orientales, y aunque no les quiero faltar al respeto, no se lo suficiente acerca de esos conjuntos de caracteres para tener una discusión inteligente acerca de las pequeñas diferencias entre caracteres FullWidth y HalfWidth.

Sumado a nuestros valores InputScope, es importante entender las otras opciones que nuestros usuarios pueden navegar en cualquier momento cuando el teclado esta en la pantalla del usuario. Aquí las tienes:

Letras Mayúsculas

15-XAML-CAPS

Emoji (hay de hecho 30 PAGINAS de emoji, haz click aquí para verlos todos)

15-XAML-Emoji

Simbolos (un segundo set de simbolos después del que se muestra con el teclado Number)

15-XAML-Symbols2

Teclado dividido (una opción del usuario, este teclado esta optimizado para escritura con pulgar)

15-XAML-SplitKeyboard

Teclado de tinta (Este teclado hace reconocimiento de escritura a mano)

15-XAML-InkingKeyboard

Obviamente, este es un gran conjunto de puntos de entrada para nosotros como desarrolladores, y proporcionando el teclado adecuado para el trabajo hará tu app más útil para tus usuarios. Hay también una distribución de teclado más, y es el del control PasswordBox. Un control PasswordBox muestra símbolos en vez de los caracteres que se escribieron, y el teclado se ve como esto:

15-XAML-PasswordBox

Notaras que también tiene un botón “Ocultar presión de teclas”. Hay veces cuando la gente puede ver tu máquina (especialmente si la estás proyectando a una audiencia) y no quieres que sean capaces de ver los teclazos de tu password. Este botón no resalta los botones cuando son tocados. (Vas a notar también que el botón de Emoji esta deshabilitado, porque esos caracteres no deben ser usados para un password.)

En el pasado, he escrito artículo acerca de TextBoxes y teclados virtuales, y revise cada uno de los casos de uso donde quieras mostrar el teclado sin mostrar lo que escribe el usuario. Un gran ejemplo de esto podría ser el juego de Ahorcado. Quieres que el usuario sea capaz de elegir una letra, pero también ocultar el teclado así el usuario puede ver su progreso.

En Windows 8, esto no es posible ya. No puedes lanzar el teclado en pantalla vía código. De hecho, establecer el foco a un control TextBox no hara nada más que hacer el cursor intermitente. Específicamente requiere que un evento tap (no un click de mouse) ocurra en el TextBox antes que aparezca el teclado en pantalla. (Esa es la misma razón de porque debes usar el Simulador al depurar este tipo de funcionalidad en tus apps.)

Resúmen

Hot, hemos cubierto una variedad de teclado que están disponibles a nuestros usuarios. Podemos aprovechar los valores InputScop para mostrar el teclado correcto en el momento correcto. Adicionalmente, aprendí que hay 30 paginas completa de caracteres Emoji para usar también. (Si no es obvio, me beneficio mucho de escribir estos artículos también!)

Si quieres ver una aplicación funcional que usa cada uno de los valores InputSCop, haz click en el icono para descargarlo:

downloadXAML

Mañana, vamos a echarnos un clavado a usar los Menus Contextuales para ofrecer a nuestro usuario comandos contextuales directamente en la pantalla de la app. ¡Hasta entonces!

downloadTheTools

Aquí esta la lista enorme de Emoji, en caso de que hayas olvidado hacerle click:

Emoji

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 14: Geo localización

March 29th, 2013 No comments

Este artículo es una traducción de “Día 14: Geo localización” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Hoy vamos a hablar acerca de uno de mis elementos favoritos e cualquier plataforma de desarrollo. Tener el conocimiento de la ubicación del usuario (o más específicamente, del dispositivo) hace mejor a cualqueir aplicación. Aquí están algunos ejemplos de como:

Aplicaciones de línea de negocios

Conoce que planta estará visitando tu gerente hoy de modo que el tenga toda la documentación apropiada para la maquinaria en esa instalación. Además tu aplicación podrá navegar e fotos y nombres de los empleados en ese lugar así ellos estarán más preparados cuando el llegue.

Juegos

Identifica otros jugadores cercanos y ten la oportunidad de retarlos a un juego. No solo mejorará potencialmente la latencia de red para ellos sino que también podrás formar un gremio de nada. Crea un juego global de parejas, basado únicamente en la proximidad, no en contacto.

Mapas

Duh. Haremos esto como una parte del código de ejemplo de hoy.

Viajes

Reconoce la distancia del usuario y tiempo de viaje potencial desde el aeropuerto y alértalos  de caer en la urgencia de perder su vuelo. Además, una vez que has establecido que no llegarán a tiempo podrás ayudarlos a encontrar el siguiente vuelo disponible sin que el usuario lo tenga que hacer por sí solo.

Ejercicio

Hay toneladas de aplicaciones disponibles para seguir tu ruta de ejercicio. Piensa en correr, ciclismo, etcétera. La aplicación de geolocalización obvia de estas aplicaciones es la habilidad de mapear la ruta que tomaste durante tus viajes. Una más importante, sin embargo, creo que es la responsabilidad que probablemente cae en los fabricantes de SO mismos, es la habilidad de reconocer un accidente. En promedio, 4500 ciclistas al año son víctimas de situaciones de accidentes, donde ellos son abandonados lastimados (o peor) en un lado del camino. En el mundo de hoy, casi todo el mundo tiene un teléfono con ellos, incluso al correr o andar en bicicleta. Imagina que tu teléfono es capaz de reconocer un impacto grande (usando información del acelerómetro o giroscopio), seguido de ningún movimiento. Después de 30 segundos de movimiento nulo, tu teléfono te incita a llamar a un número de emergencia y enviar mensajes de texto a una lista pre seleccionada de contactos con un mensaje de ayuda y tu ubicación. Después de otros 30 segundos inmediatamente llama a emergencias y envía la información. Esta funcionalidad podría salvar vidas, tantas como esos ciclistas que fallecen sin ayuda solo porque nadie sabe donde están. Siento ser tan crudo, pero es una razón importante en la cual pensar.

Como puedes ver, hay siempre una razón por la cual tomar información de ubicación y hacer tu aplicación incluso mejor. Además, si amas las ideas que te doy arriba eres completamente libre de robarlas en tu favor. Probablemente yo nunca cree ninguna de estas aplicaciones. Necesitaría haber 48 horas en un día para hacer que eso sucediera.

Actualizando nuestro manifiesto

Afortunadamente, obtener la información de nuestra ubicación geográfica es muy sencillo y como de costumbre, tenemos que declarar que la Ubicación es una de nuestras capacidades a usar. Para hacer esto, abre la sección de Capacidades de tu archivo package.appxmanifest y selecciona la caja de Ubicación.

image

Si omites este paso y solo tratas de implementar el código del resto del artículo no tendrás ningún error pero tampoco obtendrás ninguna información.

Obteniendo nuestra ubicación geográfica

En este ejemplo, he construido una aplicación que monitoree constantemente la ubicación del dispositivo del usuario. Lo primero que me confundió en este proceso fue como preguntar al usuario por permiso para iniciar la localización en la aplicación. Si revisas el Día #11 Pantalla de bloqueo, necesitamos pedir un permiso explícito del usuario para acceder a su pantalla de bloqueo. Con la ubicación, sin embargo no. El simple acto de tratar de acceder a la información le preguntará a tu usuario por ti. Para hacer esto increíblemente más fácil, aquí está TODO el código que necesitarás para acceder a la ubicación de un dispositivo desde tu aplicación (Ten en cuenta que estoy enviando todos mis valores a cajas de texto en mi MainPage.xaml que muestran la información. Todas están nombradas como [DataType]Value para hacerlo obvio).

Geolocator ubicacion;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
ubicacion = new Geolocator();
ubicacion.PositionChanged += location_PositionChanged;
ubicacion.StatusChanged += location_StatusChanged;
}

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
ubicacion.PositionChanged -= location_PositionChanged;
ubicacion.StatusChanged -= location_StatusChanged;
}

async void location_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
Geoposition posicion = args.Position;

LatitudeValue.Text = posicion.Coordinate.Latitude.ToString();
LongitudeValue.Text = posicion.Coordinate.Longitude.ToString();
AccuracyValue.Text = posicion.Coordinate.Accuracy.ToString();

TimestampValue.Text = posicion.Coordinate.Timestamp.ToString();

if (posicion.Coordinate.Altitude != null)
AltitudeValue.Text = posicion.Coordinate.Altitude.ToString()
+ "(+- " + posicion.Coordinate.AltitudeAccuracy.ToString() + ")";
if (posicion.Coordinate.Heading != null)
HeadingValue.Text = posicion.Coordinate.Heading.ToString();
if (posicion.Coordinate.Speed != null)
SpeedValue.Text = posicion.Coordinate.Speed.ToString();
});
}

async void location_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
StatusValue.Text = args.Status.ToString();
});
}

Como podrás haber adivinado, esta es una operación manejada por eventos. Cuando mi página se carga, creo un nuevo objeto de tipo Geolocator y agrego dos eventos: PositionChanged y StatusChanged.

PositionChanged es el importante. Aquí es donde obtenemos toda la información útil como Latitud, Longitud y Precisión. Todos estos valores vienen de la clase Geocoordinate y como puedes ver en el código de arriba, hay muchas más.

* Accuracy es la medida, en metros, del radio de un círculo que tenga nuestros valores de latitud y longitud como punto central. Como esto.

14-XAML-Accuracy

* Timestamp es el tiempo actual en el que el valor de la ubicación fue leído. Esto incluye información de la zona horaria así que tendrás que convertir los tiempos para almacenar todo en UTC.

* Altitude es la elevación del dispositivo, en metros. Este es probablemente encontrado en dispositivos con un barómetro (cubriremos los sensores más tarde en esta serie) pero es una pieza valiosa de información si la puedes tener.

*AltitudeAccuracy es como nuestro otro valor de precisión, excepto que es el simple margen de error para el valor de altitud. Es decir, que estás en + o – estos metros.

* Heading también será mostrado con el sensor adecuado, la brújula. Esto mide en grados relativos a nuestro norte verdadero.

* Speed puede ser técnicamente calculado al monitorear los valores de latitud/longitud cada determinado tiempo, pero ellos nos lo han hecho increíblemente fácil para nosotros. Es medido en metros/segundo pero es un valor opcional que el dispositivo GPS puede dar. Esto significa que no todos los dispositivos pueden regresar un valor.

El otro código, del ejemplo de arriba del que me gustaría hablar es acerca de la cosa async/await. Quizá hayas notado que ambos manejadores de eventos tienen async en el inicio, y que después tenemos algo como esto:

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { });

Dado que la adquisición de nuestra ubicación sucede en un hilo en segundo plano, necestiamos usar un Dispatcher para regresar a nuestro hilo primario para poder escribir nuestros valores en la pantalla. Sin este código tendremos un error en el momento que tratamos de manipular la capa de la UI dado que los hilos en segundo plano no tienen acceso a esto directamente. Aquí está como luce mi UI básica (no, no es ahí donde vivo pero podrías saberlo si checas esa ubicación):

image

Así que hemos obtenido nuesta información de ubicación pero aún está el manejador de eventos de StatusChanged que creamos antes. Esto no es algo a lo que generalmente le damos acceso a nuestro usuario es más como información administrativa para nosotros pero es un conjunto importante de información de cualquier manera. Puede tener seis diferentes valores.

* notInitialized es regresado cuando tu aplicación no ha solicitado permiso para acceder a la información de ubicación.

* disabled es el valor que obtendrás cuando el usuario rechace tu solicitud de acceder a su información de ubicación.

* notAvailable es regresado si el dispositivo del usuario no soporta la ubicación espacial.

* noData es regresado si el dispositivo del usuario soporta la ubicación pero no puede obtener ninguna. Esto podría pasar en un escenario donde el dispositivo no está conectado a Wi-Fi y está dentro de un edificio por ejemplo.

* initializing es el valor del estado que recibirás entre el momento en que el usuario autorice el acceso a su ubicación y el momento en que comiences a recibir esa información. En usos futuros de tu aplicación, este también se mandará cuando tu aplicación esté esperando a acceder a los datos de ubicación por primera vez.

* ready es la respuesta de oro y te permite saber que la información esta disponible para tu uso.

Así que el ejemplo que te he dado en este artículo te permite reconocer cada vez que la ubicación de tu usuario cambie y todas las veces que eso suceda. Si solo necesitas obtener esta información UNA SOLA VEZ, digamos, para etiquetar una imagen que el usuario acaba de tomar, solo haces una solicitud al objeto de tipo Geolocator sin tener que crear todos los eventos que he marcado arriba. En el método de abajo, podemos hacer una llamada simple al método ObtenerPosicionUnaVez en su lugar.

async private void ObtenerUbicacionUnaVez()
{
Geoposition posicion = await ubicacion.GetGeopositionAsync().AsTask();

LatitudeValue.Text = posicion.Coordinate.Latitude.ToString();
LongitudeValue.Text = posicion.Coordinate.Longitude.ToString();
AccuracyValue.Text = posicion.Coordinate.Accuracy.ToString();
}

En este caso, solo necesitamos un valor simple, una ocasión. No crees un ciclo que haga esta llamada una y otra vez, es mucho más lento y ahorrarás toneladas de recursos de la máquina siguiendo el ejemplo anterior que registró nuestros manejadores de eventos.

Usar el simulador para para fingir ubicación

Si estás usando una PC de escritorio tradicional, quizá ya has notado que tu máquina no hace un gran trabajo determinando tu posición. La ubicación por red puede ser decente pero es poco probable que tus coordenadas latitud y longitud sean muy acertadas. Entra al simulador. Puedes ajustar una ubicación específica en el simulador sin tener que estar en un avión. Para hacer esto solo abre los ajustes de ubicación del simulador.

14-XAML-SimulatorOption

En este punto, puedes darle los valores de latitud, longitud, altitud y valores de precisión:

14-XAML-SimulatorSettings

¡Ahí tienes! Puedes ahora escribir una aplicación que pueda determinar donde se encuentra el dispositivo del usuario y mientras la estás construyendo, puedes pretender que estás en cualquier parte de la tierra. No es una forma mala de viajar ¡al menos los costos son menores!

En resumen

Hoy hablamos acerca de los datos de geo localización y que tan importante puede ser para cualquier aplicación en el mercado. Vimos como seguir la ruta de un usuario, también obtener su ubicación una sola vez para aplicaciones que solo necesitan la ubicación específica “justo ahora” pero no todo el tiempo.

Si quisieras descargar una aplicación de ejemplo que incluya todo el código de este artículo, da clic en el ícono de abajo.

 

 

Mañana, vamos a ver el teclado en pantalla, InputScopes y cajas de texto. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 13: Navegación

March 28th, 2013 No comments

Este artículo es una traducción de “Día 13: Navegación” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Hemos pasado los últimos días enfocándonos mucho en actualizar el sistema con información para permitirle saber al usuario que es lo que sucede. De hecho, en los primeros 12 días esta serie hemos pasado muy poco tiempo hablando de una de las actividades más comunes que vamos a encontrar en el desarrollo de Windows 8: La navegación entre páginas con XAML.

Hoy corregiremos lo que estaba incorrecto metiéndonos en este tema. Hay tres escenarios específicos que quiero asegurarme de cubrir en este artículo:

* El simple acto de navegación de la página A a la página B. ¿Qué sucede entonces y qué información está disponible para nosotros?

* Pasar información de una página a otra. Esto no solo incluye cadenas y enteros, podemos pasar también objetos enteros entre páginas.

* Guardar el caché de las páginas. Cuando un usuario presiona el botón de retroceso, ellos no quieren descubrir que toda la información que ingresaron ha desaparecido. Discutiremos esto más adelante.

Navegar entre páginas en Windows 8 XAML

Parece que cada vez que encontramos una nueva plataforma hay también una nueva manera de navegar entre páginas en una aplicación XAML. Windows 8 no es diferente en ese aspecto. Este proceso es fácilmente explicado guiándote al momento de crear algunas páginas, así que iniciemos ahí.

Crea una nueva aplicación en blanco y después agrega dos nuevas páginas básicas en ella. Para este ejemplo puedes llamarlas PaginaA.xaml y PaginaB.xaml

image

En cada una de esas páginas, hay una línea de XAML que ajusta el el AppName.

<page .Resources>
<x:string x:Key="AppName">My Application</x:string>
</page>

Normalmente, moveríamos esto a nuesto archivo App.xaml y lo haríamos aplicar a todas las páginas de nuestra aplicación. Por hoy, vamos a usar este mecanismo simple para darle a cara una de nuestras páginas un nombre distinto que podamos ver cuando esté cargada. Ajusta el valor de PaginaA a “Página A” y el de PaginaB a “´Página B” de modo que tus páginas luzcan así:

image image

Para hacer el ejemplo sencillo de usar, también vamos a hacer un cambio rápido a nuestro archivo App.xaml.cs. Cerca del fondo del método OnLaunched() está algo de código que luce como lo siguiente.

if (rootFrame.Content == null)
{
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}

Vamos a querer cambiar la referencia de typeof(MainPage) a typeof(PaginaA). Como se muestra a continuación:

if (rootFrame.Content == null)
{
if (!rootFrame.Navigate(typeof(PaginaA), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}

Esto causará que tu aplicacion arranque con PaginaA como página inicial. Hasta este punto, ejecuta tu proyecto. Verás que comienza la pantalla de inicio y después PaginaA aparecerá. Deberías notar que incluso aún cuando en Visual Studio apareceuna flecha cerca del título de nuestra página esta enlazada a si es posible o no la página de “ir hacia atrás” con la propiedad Frame.GoBack. Hablaremos de ello más adelante.

Por ahora, vamos a la navegación. Has visto técnicamente como hacerlo desde App.xaml.cs pero luce un poco diferente cuando vayas de página en página. He agregado un control de tipo botón a mi archivo PaginaA.xaml.cs justo antes de la sección VisualStateManager. El XAML luce así:

<button x:Name="btnPagina"
Grid.Row ="1"
Content="A página B"
Width="150"
Height="150"
Click="btnPagina_Click"></button>

 

En el manejador de eventos para el botón, escribimos nuestra primera sentencia de navegación (¡finalmente!).

private void btnPagina_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(PaginaB));
}

Como puedes ver es un proceso muy sencillo. Lo vamos a hacer más complicado ahora al agregar a un nuevo botón a la página B. Esto podría parecer una tarea repetitiva pero notarás que podemos meternos en problemas rápidamente (deberías ejecutar tu proyecto en este momento para asegurar que de hecho navegas a tu página B). Agrega el mismo botón y su manejador de eventos en Pagina B pero obviamente apuntando a página A en esta ocasión. Ahora tienes un botón en cada página que apunta a la otra. Si tu solo usas estos botones para hacer tu navegación vas a terminar creando una GRAN fila de navegación de retroceso y esto hará al concepto del botón de regreso completamente irrelevante. Lo que necesitamos hacer en este caso es implementar un manejador de eventos para GoHome que es parte del objeto LayoutAwarePage que estamos usando. Para ilustrar efectivamente este ejemplo, agrega un segundo botón en tu PaginaB.xaml con un nuevo manejador de eventos. En este manejador de eventos, sin embargo no vamos a navegar a una página. En su lugar vamos a crear un evento GoHome y llamarlo. Lucirá así:

private void btnPagina_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
if (this.Frame != null)
{
while (this.Frame.CanGoBack) Frame.GoBack();
}
}

private void btnHome_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
base.GoHome(sender, e);
}

Como puedes ver, nuestro método GoHome ejecuta un ciclo rápido intentando “Volver” hasta que ya no pueda más. En este punto, terminamos en la cima de la fila de navegación en nuestra página inicial. Es un buen truco, pero creo que se ilustrará mejor con un video breve.

Pasar información entra páginas en Windows 8

Después, vamos a querer pasar información entre páginas. Quizá un objeto, quizá una cadena, información en todo caso. Mientras se retira, nuestro método Frame.Navigate() es sobrecargado para poder aceptar un parámetro de información. Para este ejemplo he agregado un TextBox y un Button a mi página A pero ahora voy a asumir que sabes como hacer esto. La parte importante de esto es donde tengo un manejador de eventos que envíe el valor del texto del TextBox y lo envíe como parte del método Navigate(). Como lo siguiente:

private void btnPagina_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(PaginaB), txtMensaje.Text);
}

Por otro lado, en la páginaB necesitamos atrapar esta información y desplegarla. De nuevo, he agregado un TextBlock en mi código de ejemplo (el cual podrás descartar al final del artículo) pero la pieza importante es mi nuevo manejador para el evento OnNavigatedTo() y atrapar la información cuando llegue.

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

string mensaje = e.Parameter as string;

if (!string.IsNullOrWhiteSpace(mensaje))
{
txtRecibido.Text = mensaje;
}
else
{
txtRecibido.Text = "Necesitas recibir una cadena. Regresa e ingresa un valor";
}
}

En la página B podremos recoger el valor obtenido de NavigationEventArgs.Parameter, donde lo estoy convirtiendo a valor de cadena. Necesitarás convertir tu valor a un tipo apropiado antes de que puedas utilizarlo, pero una vez que lo hayas hecho, podrás ¡pasar datos de una página a otra!

Además, mencionéantes que puedes pasar objetos completos, usando este mecanismo también. ¿Recuerdas nuestra clase Elemento del Día 4? Voy a pasar un Elemento personalizado de la página A a la página B en el siguiente ejemplo. Aquí está el código de la página A:

private void btnGalio_Click(object sender, RoutedEventArgs e)
{
Frame.Navigate(typeof(PaginaB), new Elemento
{
NumeroAtomico = 31,
PesoAtomico = 69.72,
Categoria = "Otros metales",
Nombre = "Galio",
Simbolo = "Ga",
Estado = "Sólido"
});
}

Puedes ver claramente que estamos pasando un elemento completamente nuevo a la página B. Aquí está la manera de atrapar esta información en la página B.

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

Elemento elementoRecibido = e.Parameter as Elemento;
txtRecibido.Text = elementoRecibido.Categoria;
}

Creando caché de páginas para un mejor rendimiento del botón de regreso

La última cosa que queremos manejar relacionado a la navegación es el caché de las páginas. Para este ejemplo final estoy usando nuestra aplicación de ejemplo en el estado donde estaba pasando valores de cadenas hacia atrás y adelante. Quizá hayas notado, si construiste tu propia aplicación de ejemplo que si escribes algo en el texto de la página A y envías la información a la página B, cuando presiones el botón de volver y regreses a la página A, esta no recordará lo que has escrito en la caja. Este es un patrón de experiencia de usuario increíblemente frustrante que puedes ver en la web todo el tiempo.

Podemos evitar esto con una simple línea en el constructor de las páginas a las que queremos crearles caché.

public PaginaA()
{
this.InitializeComponent();
NavigationCacheMode = NavigationCacheMode.Enabled;
}

Después de que ajustes el NavigationCacheMode, encontrarás que los valores del TextBox (y todo lo demás en tu página) permanecerán al momento de regresar. Dale una prueba, es una mucho mejor experiencia y no requiere que nosotros llenemos y rellenemos la forma cada vez que el usuario regrese a la página.

En resumen

Esta es una vista extensa de la nevegación en aplicaciones XAML para Windows 8. Cubrimos la manera de movernos entre páginas, pasar datos entre páginas y atrapar estas páginas para cuando el usuario de clic en los botones de volver.

Si quisieras descargar el código completo de este artículo, puedes dar clic sobre el ícono de abajo. (Nota por favor que el botón del Galio está deshabilitado, necesitarás eliminar los comentarios para el manejador de eventos para este botón, también como el código en la página B para hacerlo funcionar. La página B solo puede aceptar un tipo de parámetro a la vez y está actualmente listo para la cadena).

 

 

Mañana, vamos a iniciar nuestra conversación determinando la ubicación actual de un usuario usando GeoLocalización, incluyendo las reglas que van al usar esta tecnología. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 12: Tareas en segundo plano

March 21st, 2013 No comments

Este artículo es una traducción de “Día 12: Tareas en segundo plano” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Hoy, vamos a hablar acerca de las tareas en segundo plano. La vía pequeña para describir una tarea en segundo plano es esta:

Una tarea en segundo plano es el código que corre cuando tu aplicación no.

Piensa en estos escenarios.

* Audio vía streaming continuo, incluso cuando el usuario esta ejecutando otra aplicación.

* Actualizar el mosaico de la aplicación para reflejar nuevos datos.

* Mostrar una notificación toast para hacerle saber al usuario que nueva información ha sucedido.

* Actualizar la pantalla de bloqueo, incluso cuando el dispositivo esta bloqueado.

Obtener una tarea en segundo plano establecida y registrada con el sistema es un proceso de dos pasos. Primero, tienes que registrar la tarea en segundo plano en tu archivo package.appxmanifest. Una vez que ha sido hecho, aún necesitas registrar los eventos de la tarea con el sistema del código de tu aplicación y después están los eventos adicionales para controlar lo que sucede cuando la tarea en segundo plano finaliza. Cubriremos estos escenarios en este artículo.

Crear una clase de tarea en segundo plano

Mi primer paso es siempre crear un proyecto secundario que contendrá mis tareas en segundo plano. No es requerido pero es una buena separación visual de tu código.

12-XAML-AddProject

Cuando creas un proyecto, elige “Windows Runtime Component” como el tipo de proyecto.

12-XAML-WindowsRuntimeComponent

Por defecto, tendrás una clase llamada Class1.cs. Puedes renombrarla si gustas o solo eliminarla y agregar una nueva clase al proyecto. En cualquier caso, vas a crear una nueva clase llamada ActualizarMosaico.cs

Ahora, las tareas en segundo plano deben implementar una interfaz muy específica: IBackgroundTask. Esta solo implementa un método, Run(), este método es el que llamaremos cuando nuestra aplicación inicie la tarea en segundo plano. Solo para que inicies, aquí está como luce mi código C# después de implementar la interfaz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;

namespace AgenteSegundoPlano
{
class ActualizarMosaico : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
//Agregaremos código aquí después
}
}
}

He agregado un comentario donde nuestro código residirá, pero por ahora es un buen inicio.

Configurando tu archivo Package.appxmanifest

El siguiente paso en este proceso es declara que usaremos las tareas en segundo plano en esta aplicación. Hacemos esto en el archivo package.appxmanifest en la sección de Declaraciones como se muestra en la imagen de abajo.

image

Como puedes ver , he agregado una declaración para la tarea en segundo plano (necesitarás una nueva de estas por cada tarea en segundo plano que quieras agregar en tu proyecto), y ajustar el punto de entrada a AgenteSegundoPlano.ActualizarMosaico, nuestra nueva clase. Después, necesitamos registrar esta tarea in nuestra aplicación actual de modo que Windows 8 lo sepa ejecutar en los momentos adecuados.

Registrando tu tarea en segundo plano

Vamos a tomar un par de pasos en este código de nuestro MainPage.xaml.cs, iniciando con checar si nuestra tarea en segundo plano ha sido ya registrada en el sistema. Yo generalmente hago esto tan pronto como la página se cargue en mi método OnNavigatedTo(). He creado un nuevo método llamado VerificarRegistroTarea() que verifique este estado por mí y ajuste un valor booleano global en la página. Tu puedes de hecho hacer esto en tu archivo App.xaml.cs también pero para nuestros propósitos simples, esta ubicación bastará.

bool estaTareaRegistrada = false;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
VerificarRegistroTarea();
}

private void VerificarRegistroTarea()
{
foreach (var tarea in BackgroundTaskRegistration.AllTasks)
{
if (tarea.Value.Name == "ActualizarMosaico")
{
estaTareaRegistrada = true;
break;
}
}
if (!estaTareaRegistrada)
{
RegistrarTarea("ActualizarMosaico", "AgenteSegundoPlano.ActualizarMosaico");
}
}

Como puedes ver, estamos recorriendo a través de la colección BackgroundTaskRegistration.AllTasks porque podríamos tener muchas tareas en segundo plano ejecutándose bajo de nuestra aplicación y en este caso yo solo estoy interesado en uno: ActualizarMosaico. Puedes también ver que he hecho una llamada a RegistrarTarea() si la tarea no está aún registrada.

Depende de ti como manejar este caso pero en mi aplicación yo quiero asegurarme de que mi tarea en segundo plano esté siempre registrada y si ha sido eliminada del registro por alguna razón, quiero agregarla de nuevo. Así es como luce mi método RegistrarTarea().

private void RegistrarTarea(string nombre, string puntoEntrada)
{
BackgroundTaskBuilder tareaSegundoPlano = new BackgroundTaskBuilder();
tareaSegundoPlano.Name = nombre;
tareaSegundoPlano.TaskEntryPoint = puntoEntrada;
tareaSegundoPlano.SetTrigger(new SystemTrigger(SystemTriggerType.InternetAvailable, false));
BackgroundTaskRegistration tarea = tareaSegundoPlano.Register();
}

Puedes ver que estoy pasando el valor del nombre y punto de entrada pero puedes de hecho establecer estos valores dependiendo de tu situación. Dado que esta aplicación podría tener múltiples tareas en segundo plano, he decidido hacer esta construcción un poco más simple y pasarlos en algunos parámetros.

En nuestro método de registro, creamos un objeto de tipo BackgroundTaskBuilder(), ajusta el nombre y punto de entrada y después determina un SystemTrigger que ejecutará nuestra tarea en segundo plano. En este caso, he elegido el lanzador fácilmente probable InternetAvailable. Para probarlo, estaremos cortando el acceso a internet en nuestra máquina.

Si en algún momento necesitas eliminar el registro de la tarea en segundo plano es muy sencillo. Aquí está el método de ejemplo EliminarRegistroTarea() que puedes usar para eliminar la tarea.

private void EliminarRegistroTarea(string nombre)
{
foreach (var tarea in BackgroundTaskRegistration.AllTasks)
{
if (tarea.Value.Name == nombre)
{
tarea.Value.Unregister(true);
}
}
}

En ese ejemplo revisamos a través de las tareas que están registradas de nuevo y si encontramos alguna de ellas con el nombre que estamos buscando llamamos al método Unregister() confirmándolo con el parámetro en verdadero.

Así que hemos trabajado con la forma de registrar o eliminar el registro de nuestra tarea en segundo plano y ahora hemos especificado que nuestra aplicación debería lanzar nuestra tarea en segundo plano cuando la zona horaria de nuestra máquina cambie. Vamos a escribir algo de código en nuestra clase AgenteSegundoPlano y después darle una prueba a esto.

Haciendo que tu tarea en segundo plano HAGA algo

Antes, hemos creado un archivo llamado ActualizarMosaico.cs en nuestro nuevo proyecto de tipo Windows Runtime Component y dejamos un espacio en blanco para agregar código en el método Run() que debe ser implementado como parte de la interfaz IBackgroundTask. Aquí está como debería lucir el archivo con el código para actualizar nuestro mosaico.

public void Run(IBackgroundTaskInstance taskInstance)
{
XmlDocument datosTile = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquareText04);
XmlNodeList datosTexto = datosTile.GetElementsByTagName("text");
datosTexto[0].InnerText = "Actualizar mosaicos es absolutamente genial. #31daysofwin8";
TileNotification notificacion = new TileNotification(datosTile);
notificacion.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(30);
TileUpdateManager.CreateTileUpdaterForApplication().Update(notificacion);
}

Obviamente, podríamos escribir una tarea en segundo plano similar para implementar el envío de una notificación toast, actualizar la pantalla de bloqueo u otras llamadas a servicios web por ejemplo.

En resumen

Hay una cosa más a notar acerca de las tareas en segundo plano: son mucho más complejas de depurar que el código en tu aplicación. De hecho Microsoft ha escrito un artículo entero acerca de como depurar exactamente las tareas en segundo plano. Yo recomiendo ampliamente leerlo. Ellos han creado también un tutorial de inicio rápido llamado Crear y Registrar una tarea en segundo plano.

Si quisieras descargar el código de ejemplo funcional de este artículo, da clic sobre la imagen de abajo.

 

 

Mañana, vamos a doblar por completo de nuevo y comenzaremos a hablar acerca de navegación. Específicamente como navegar entre páginas en una aplicación XAML y pasar parámetros como información entre páginas como parte del proceso. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 11 Notificaciones en la pantalla de bloqueo

March 20th, 2013 No comments

Este artículo es una traducción de “Día 11: Notificaciones en la pantalla de bloqueo” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Hoy cubrimos la última parte de notificaciones en Windows 8: La pantalla de bloqueo. Si estás corriendo Windows 8 en tu máquina es probable que te hayas familiarizado con la pantalla de bloqueo. Te muestra cuantos correos has recibido, mensajes de Facebook, el reloj y tu el estado de tu conectividad. Aquí está mi pantalla de bloqueo:

11-XAML-LockScreen

Si, esta es una foto de mi pantalla. Pasé 30 minutos esta mañana encontrando una solución para tomar una captura de mi pantalla de bloqueo sin éxito (si, lo se, pude haber creado una MV o una remota en máquina pero no cuento con nada de eso en este momento). De cualquier manera, puedes ver que solo estoy escribiendo este artículo a unos días antes de la fecha de publicación y tengo una reunión en 30 minutos.

Nosotros, como desarrolladores, tenemos la habilidad de agregar nuestros íconos a esta pantalla también pero es peligroso hacerlo así nada más. Toma esto. Es la guía de Microsoft de las mejores maneras de utilizar el área de notificaciones de la pantalla de bloqueo.

Configurando nuestro manifiesto

Primero, necesitamos ajustar nuestro package.appxmanifest para permitir las notificaciones de la pantalla de bloqueo.

11-XAML-ApplicationUITab

Cuando haces esto, notarás que se aparecen pequeños símbolos rojos con una X. Cuando las notificaciones están habilitadas somos requeridos para tener un logo “badge” y dado que elegimos la opción que incluye actualizaciones por mosaicos también somos requeridos  para dar una imagen de logo ancha. Aquí esta la tabla de UI de la aplicación con esos archivos agregados.

11-XAML-ApplicationUITab2

Notarás que ahora tienes una X roja lo cual nos hace saber que “Si las notificaciones de pantalla están habilitadas, debes especificar una o más declaraciones de tareas en segundo plano del tipo ‘Timer’, ‘Control channel’ o ‘Push notifications’”.

Lo que significa es que las aplicaciones con la pantalla de bloqueo esperan ser actualizadas a paritr de un agente en segundo plano. Vamos a movernos a nuestra tablas de Declarations y agregar las tareas en segundo plano como esto:

11-XAML-Declarations

En mi aplicación de ejemplo, sin embargo, vamos a crear una tarea en segundo plano. Voy a cubrir esto extensivamente mañana. En su lugar vamos a enfocarnos específicamente en los procesos y el código que nos permite actualizar nuestra información en la pantalla de bloqueo.

Pidiendo permiso

Antes de siquiera comenzar a pensar acerca de escribir contenido en la pantalla de bloqueo del usuario necesitas pedir permiso de tu usuario. Ahora, no TIENES que preguntar pero sin preguntar por permiso el camino a la pantalla de bloqueo es complicado y casi cayendo en lo peligroso. Aquí esta lo que quiere decir.

Tu solo tienes UNA y solo UNA oportunidad para pedir por la autorización del usuario para estar en su pantalla de bloqueo. Si preguntas una vez y ellos dicen “No permitir”, no serás capaz de preguntar de nuevo. Aquí está como parece cuando preguntas.

11-XAML-BackgroundRequest

Y así es como lo haces:

BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();

Si nunca preguntas, la única manera de llegar a la pantalla de bloqueo es para que el usuario abara sus configuraciones de PC y explícitamente te agregue, como esto (ignora por favor la horrible imagen de mi cara sin afeitar a menos de que quieras soportar mi campaña Movember):

11-XAML-LockScreenSettings

Los usuarios pueden seleccionar hasta 7 aplicaciones para msotrarse en su pantalla de bloqueo. Queremos asegurarnos que somos una de ellas. Así que porque nuestro estado puede cambiar el ánimo del usuario deberíamos ser responsables antes de mandar actualizaciones a su pantalla de bloqueo.

Asegurándonos de que tienes permisos

Este no es un paso requerido. Puedes tener tu aplicación o tarea en segundo plano (como lo veremos mañana) enviando continuamente actualizaciones incluso si no tienes permiso. Dicho esto, tus actualizaciones tampoco serán vistas por el usuario. Sin permiso, tus actualizaciones desaparecerán en el limbo.

Aquí es como verificamos si el usuario nos ha dado permisos para actualizar la pantalla de bloqueo.

BackgroundAccessStatus status = BackgroundExecutionManager.GetAccessStatus();

if ((status == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity) ||
(status == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity))
{
//ENVÍA AQUÍ TU ACTUALIZACIÓN.
}

Así que hasta este punto, hemos cubierto la posibilidad de  permisos del usuario  y después asegurarte de que el permiso ha sido garantizado. El siguiente paso es de hecho enviar la actualización.

Actualizando la pantalla de bloqueo

Enviar una actualización lucirá muy familiar si has leído los dos artículos previos (Día 9: Mosaicos, Día 10: Notificaciones). Como en esos ejemplos previos, vamos a utilizar una plantilla que consiste en XML (en este caso, es increíblemente simple):

<badge value="badge_value"></badge>

Después, necesitamos especificar el valor que queremos mostrar. Tenemos muchas opciones en este escenario. No solo podemos usar cualquier número del 1 – 99, sino también tener un número de íconos para elegir. La mejor parte es que la plantilla es lo suficientemente inteligente para reconocer la diferencia así que la única cosa que cambiará en nuestro código es  el valor actual que pasamos. Aquí está el código para hacer la actualización del elemento.

 private void btnPantallaBloqueo_Click(object sender, RoutedEventArgs e)
{
BackgroundAccessStatus status = BackgroundExecutionManager.GetAccessStatus();

if ((status == BackgroundAccessStatus.AllowedWithAlwaysOnRealTimeConnectivity) ||
(status == BackgroundAccessStatus.AllowedMayUseActiveRealTimeConnectivity))
{
XmlDocument datosElemento = BadgeUpdateManager.GetTemplateContent(BadgeTemplateType.BadgeNumber);
XmlNodeList xmlElemento = datosElemento.GetElementsByTagName("badge");
((XmlElement)xmlElemento[0]).SetAttribute("value", "Playing");

BadgeNotification badge = new BadgeNotification(datosElemento);
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Update(badge);
}
}

Puedes ver que en el método SetAttribute() paso el valor de 31. Esto resulta en el elemento que se muestra en la pantalla de bloqueo que luce como lo siguiente.

WP_20121106_004

Si pudiéramos elegir usar uno de los íconos, aquí esta una lista de los que está disponible, cortesía de la página de vistas de íconos de la página de MSDN.

11-XAML-GlyphList

Para especificar un glifo, necesitamos cambiar el valor en el método SetAttribute() como a continuación se muestra.

[sourcecode lang=”csharp”]((XmlElement)badgeXML[0]).SetAttribute(“value”, “Playing”);[/sourcode]

Eso es todo acerca de las aplicaciones con pantalla de bloqueo. Espero que hayas aprendido algo hoy. Espera hay una cosa más. Olvidé mencionar que cuando elegimos “Badge and Tile Text” en nuestro manifiesto appxmanifest, habilitamos los elementos que creamos para aparecer en nuestro mosaico también (Esta es la razón por la que WideTile.png fue requerido). Aquí es cuando el mosaico luce igual que el mismo elemento de “Reproducir” aplicado.

11-XAML-WideLogo

En resumen

Podemos actualizar la información de nuestra pantalla de bloqueo de nuestra aplicación en cualquier momento, pero la parte truculenta es obtener el permiso del usuario. Una vez que lo has tenido, actualizar la información es bastante simple como pudimos ver en este artículo.

Si quisieras descargar una aplicación funcional que utiliza el código de este artículo da clic en la imagen.

 

 

Mañana, vamos a unir estos tres días de hablar acerca de tareas en segundo plano. Te mostramos como actualizar mosaicos, notificaciones e información de la pantalla de bloqueo de una tarea en segundo plano. ¡Nos vemos!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 10: Notificaciones

March 17th, 2013 No comments

Este artículo es una traducción de “Día 10: Notificaciones” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Ayer, pasamos algo de tiempo viendo los mosaicos y como dejar que los usuarios supieran acerca de notificaciones importantes desde tu aplicación. Hoy vamos a ver un tipo diferente de notificación para el usuario: Notificaciones toast.

Si no has trabajado con Notificaciones en el pasado, la palabra quizá suene un poco ridícula para ti. La palabra “toast” en este caso viene de la imagen de una pieza de pan tostado emergiendo de nuestro tostador. Nuestras notificaciones aparecen de una manera similar, mostrándose frente a nuestro usuario para hacerle saber que algo interesante ha sucedido.

La diferencia primaria entre las notificaciones y los mosaicos es que los mensajes de notificaciones aparecerán en la pantalla del usuario sin importar que aplicación se esté ejecutando en el momento. Los mosaicos tienen que ser vistos por el usuario en su pantalla de inicio.

Los mensajes de notificaciones gritan “NECESITAS SABER ESTO ¡AHORA MISMO!” donde los mosaicos son significativamente más pasivos. Asegurate de considerar esto cuando envíes mensajes. Si comienzas a mandar muchos mensajes sin sentido tus usuarios deshabilitarán la función de enviar notificaciones o peor aún desinstalarán tu aplicación. Asegurate de tener un tiempo para leer la guía de Microsoft acerca de notificaciones antes de comenzar a meterte aún más en esto.

Para referencia, aquí hay algunos ejemplos de notificaciones.

ToastText01 example

ToastImageAndText01 example

Así como los mosaicos activos, hay un catálogo entero de tipos de notificaciones que puedes usar pero iremos a ello en un momento.

Habilitando las notificaciones en tu aplicación

Nuestro primer paso a la grandeza con las notificaciones es de hecho habilitarlas en el manifiesto de la aplicación. Abre tu archivo manifiesto y ve a la tabla de “Application UI”, selecciona “Si” desde la lista en la opción “Toast capable”.

image

Será muy tentador en lo que recorres este artículo crear un archivo “Bagde” y subirlo a tu aplicación, pero para este tutorial no lo hagas. Aquí está el porqué:

Si subes un archivo de este tipo deberás habilitar las notificaciones de pantalla bloqueada. Sin embargo si estás son habilitadas debes contar con una tarea de segundo plano. No estamos cubriendo las tareas en segundo plano  por dos días más y las actualizaciones de pantalla bloqueada son mañana. Solo se paciente.

Hoy nos enfocaremos en notificar al usuario vía mensajes. Vamos a hacerlo

Lanzar una notificación desde tu aplicación

Ayer, en el día 9, si lo leíste, entonces lanzar una notificación te será increíblemente familiar. Aquí está el código que necesitas para lograrlo.

ToastTemplateType tipoNotificacion = ToastTemplateType.ToastImageAndText02;
XmlDocument xmlToast = ToastNotificationManager.GetTemplateContent(tipoNotificacion);
XmlNodeList textoToast = xmlToast.GetElementsByTagName("text");
XmlNodeList imagenesToast = xmlToast.GetElementsByTagName("image");
textoToast[0].InnerText = "Gato curioso";
textoToast[1].InnerText = "Este gatos parece que esta queriendo comer tu cara.";
((XmlElement)imagenesToast[0]).SetAttribute("src", "ms-appx:///Assets/10-XAML-CatImageSmall.png");
((XmlElement)imagenesToast[0]).SetAttribute("alt", "Cara de gato espantado");

ToastNotification toast = new ToastNotification(xmlToast);
ToastNotificationManager.CreateToastNotifier().Show(toast);

Como lo hicimos con los mosaicos lo hacemos con las notificaciones. La primera línea selecciona nuestra plantilla. Después agarramos el XML para esa plantilla y lo almacenamos en xmlToast. Aquí está como luce la plantilla de ese XML.

<toast>
<visual>
<binding template="ToastImageAndText02">
<image id="1" src="image1" alt="image1"></image>
<text id="1">headlineText</text>
<text id="2">bodyText</text>
</binding>
</visual>
</toast>

Como puedes ver, tenemos dos propiedades de texto y una propiedad de imagen. Los siguientes pasos en nuestro código de ejemplo de arriba fueron asignar valores a esas propiedades. Para la imagen notarás que he agregado una línea adicional esta ocasión haciendo referencia al atributo “alt”. Si has hecho algo de desarrollo web antes probablemente ya conoces que es, pero es una pieza importante para historia de la accesibilidad en Windows 8. Te da la representación en texto de una imagen, para aquellos usuarios que son incapaces de ver su pantalla.

Finalmente creamos un nuevo objeto de tipo ToastNotification y lo mostramos con el método Show(). Esta es la simple historia acerca de crear notificaciones en Windows 8. Y así es como lucirá en mi máquina:

10-XAML-CatToast

 

Pero espera ¡Aún hay más! Si creaste un proyecto  y lanzaste un mensaje de notificación quizá hayas notado que hay un sonido que lo acompaña. Este es el sonido por defecto de la notificación, pero tienes opciones. Hay algunas otras cosas que de hecho puedes hacer con las notificaciones.

Ajustar el audio para una notificación (¡y mas!)

Todo lo relacionado a crear una notifcacion permanece igual, pero podemos agregar algunos nodos adicionales a nuestro XML para seleccionar un sonido diferente, ajustar la duración del mensaje e incluso determinar la página a mostrar cuando la notificación sea presionada (¡con parámetros de consulta también!).

Primero, a pesar de nuestro audio tengo algunas malas noticias. No puedes usar tu propio archivo de audio. Se que esperabas deleitar a tu usuario con el sonido de un pan expulsado de la tostadora pero simplemente no es posible. En lugar de ello puedes seleccionar de una lista de nueve archivos de audio, cuatro de los cuales son sonidos cíclicos que pueden ser usados como tonos de llamada o alarmas. Puedes ver la lista de archivos de audio y descriptores disponibles para las notificaciones aquí.

Para ajustar el audio primero necesitamos modificar el XML que hemos estado creando. Por defecto ninguna de las plantillas de las notificaciones cuentan con un nodo de audio determinado así que necesitamos crear una. Lo primero en lo que necesitamos enfocarnos es en el nodo <toast> de nuestra plantilla y después podemos establecer nuestras opciones. En el código de ejemplo de abajo he incluido la misma notificación de antes pero con algunos comentarios explicando las líneas nuevas para las características opcionales.

private void btnOpcionesNotificaciones_Click(object sender, RoutedEventArgs e)
{
ToastTemplateType tipoNotificacion = ToastTemplateType.ToastImageAndText02;
XmlDocument xmlToast = ToastNotificationManager.GetTemplateContent(tipoNotificacion);
XmlNodeList TextoToast = xmlToast.GetElementsByTagName("text");
XmlNodeList imagenesToast = xmlToast.GetElementsByTagName("image");
TextoToast[0].InnerText = "Gato curioso";
TextoToast[1].InnerText = "Este gatos parece que esta queriendo comer tu cara.";
((XmlElement)imagenesToast[0]).SetAttribute("src", "ms-appx:///Assets/10-XAML-CatImageSmall.png");
((XmlElement)imagenesToast[0]).SetAttribute("alt", "Scary Cat Face");

//Este es el código de opciones lo cual es todo lo opcional basado en tus necesidades
IXmlNode nodoToast = xmlToast.SelectSingleNode("/toast");

((XmlElement)nodoToast).SetAttribute("duration", "long");

XmlElement nodoAudio = xmlToast.CreateElement("audio");
nodoAudio.SetAttribute("src", "ms-winsoundevent:Notification.Looping.Alarm");

//Debe ser usado cuando un audio cíclico ha sido seleccionado
nodoAudio.SetAttribute("loop", "true");
nodoToast.AppendChild(nodoAudio);

//Puedes colocar cualquier texto que te guste en la propiedad
//opcional de lanzamiento, pero al presionar una notificación el mensaje te deberá llevar
//a algo contextualmente relevante.
((XmlElement)nodoToast).SetAttribute("launch", "<cat state='angry'><facebite state='true'></facebite></cat>");

ToastNotification toast = new ToastNotification(xmlToast);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}

Es importante recordar que todas estas características son opcionales, puedes verificarlo por su ausencia en nuestro primer ejemplo. Aquí hay un par de cosas para recordar acerca de estas opciones:

Los mensajes de notificación  de larga duración están hechos para cosas como llamadas VOIP y alarmas de reloj, no para las notificaciones de correo. Utilízalas poco.

Todas las opciones de audio cíclicas que están disponibles solo trabajarán si has ajustado la duración a Long.

Las opciones de audio cíclico solo trabajarán si también ajustaste el atributo “loop” a verdadero.

Fallar en algunas de estas reglas resultará en que se reproducirá el audio Notification.Default en su lugar.

En adición, quizá quieres tener SILENCIO para su notificación en lugar de cualquiera de las opciones de audio. Puedes hacerlo, en ese caso especificarás un audioNode pero ajusta un nuevo atributo, silent a true como en lo siguiente.

audioNode.SetAttribute(“silent”, “true”);

Esto resultará en silencio, pero fuera de ello será una notificación normal para el usuario. Finalmente, hay un atributo “launch”. Dentro de este podemos pasar cualquier cadena de texto que quisieramos y será pasada de regreso a nosotros como parámetro para la página cuando la notifiación sea presionada por el usuario. Esta información nos deberá permitir determinar a que página debemos apuntar que información la llenará. No pongas nada en el parámetro “launch” que no necesite hacer este viaje.

En resumen

Eso es todo acerca de las notificaciones en Windows 8. Muy similares a los mosaicos, los mensajes son una gran manera de obtener la atención inmediata del usuario sin importar que es lo que están haciendo. Algunos de ustedes quizá se estén preguntando como hacer esas actualizaciones desde una tarea en segundo plano y solo te pido paciencia. Qusimos asegurarnos de darte una base sólida de cada uno de estos tipos de notificación antes de meternos por completo a los agentes en segundo plano. Solo estás a dos días de este tema, lo prometo.

Si quieres descargar el código fuente completo de este artículo da clic sobre la siguiente imagen:

 

 

Mañana,cubriremos nuestro último tema en el mundo de las notificaciones. La pantalla de bloqueo. ¡Hasta entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 9: Live Tiles

March 17th, 2013 No comments

Este artículo es una traducción del Día #9 de la serie 31 días de Windows 8 de Jeff Blakenburg.

Hoy cubriremos un tema muy importante: Live Tiles. Como hemos mencionado en artículos anteriores, tu tile es una de las partes más importantes del éxito de tu aplicación, y es una de las más ignoradas.

Tus tiles representan tu relación con tu usuario. Ellos cariñosamente lo pinean en su pantalla de inicio, lo acomodan con apps similares, incluso deciden si quieren que sea grande o pequeña. Tu trabajo es hacer el tile tan responsivo y acorde a sus necesidades como sea posible. Esto lo hacemos enviándole actualizaciones útiles al tile. Aquí hay algunos ejemplos de algunas de mis apps favoritas:

Como mencione antes, Soy un gran fan de Jetpack Joyride, pero su tile es excelente también. Aquí hay un tour de los cinco estados por los que rota, recordándome mi score más alto, así como los logros que aún no he completado. Estas actualizaciones me han llevado de regreso al juego más de una ocasión.

clip_image001clip_image002

clip_image003clip_image004

La aplicación del clima, por otra parte, nunca se voltea. Pero también no necesito nada más que lo que un tile estático me puede proveer cuando se trata del clima. Obtengo la temperatura más alta, más baja y la actual. El pronóstico del clima esta siempre a un click de distancia.

clip_image005

Finalmente, respecto a tiles, creo que la app de Fotos es mi favorita. No se aun que tan frecuentemente actualiza el set de rotación de fotos, o incluso que librerías usa, pero parece siempre tener alguna gran vieja foto en el tile que me hace recordar ese evento. Aquí hay algunos pantallazos:

clip_image006clip_image007

Tengo miles y miles de viejas fotos almacenadas en mi librería de fotos (si, están respaldadas en línea, gracias), y obtener un vistazo del pasado diariamente es grandioso.

Las Reglas

Cuando trabajamos en nuestras apps, he descubierto que hay algunas reglas que necesitamos tener en cuenta:

· Primero, lee, y después re-lee los Directrices para Live Tiles. Son extensos, pero interesantes.

· Debes SIEMPRE tener un tile pequeño. Los tiles anchos son deseables, pero DEBES tener un tile pequeño.

Los tiles pequeños no son siempre tan interesantes como sus hermanos mayores, pero aun así pueden transmitir información interesante. Aquí están los tiles pequeños de las tres apps que mostre antes:

clip_image008clip_image009clip_image010

Probablemente solo por restricciones de espacio, el tile de Jetpack no se actualiza. Sin embargo las apps de Clima y Fotos me dan todos los mismos datos que obtengo en los tiles largos, solo que en un paquete más pequeño.

Mientras estaba investigando las diferentes formas en las que un tile puede verse, me preocupe de que éste artículo fuera a ser SUPER largo después de mostrar un ejemplo de cada plantilla de tile posible. Pero resulta, sin embargo, que Microsoft ha provisto una página grandiosa que muestra cada plantilla de tile, todas las 45 de ellas. Asegurate de revisarla. Definitivamente te ayudará a elegir la plantilla de tile que es apropiada para ti, y provee el marcado XML que necesitaras también.

DEBES LEER: Catálogo de plantillas de icono

Entonces, ¿Cómo hacer a nuestro tile bailar? Vamos a empezar.

Actualizando el Tile Estático Por Defecto

Por defecto, obtienes un icono en tu app que se ve como esto:

clip_image011

(Agregue un fondo ligeramente gris a este para que puedas verlo con fondo blanco, el tuyo se verá más transparente.) Si solo quieres un tile estático que use su propia imagen de 150 x 150, puedes hacerlo de dos formas:

· Remplaza la imagen que actualmente reside en Assets/Logo.png en tu proyecto.

· Actualiza tu archivo Package.appxmanifest, y cambia el valor de Logo a una imagen diferente en tu proyecto, así:

clip_image012

OK, suficiente de la parte aburrida. ¡Escribamos algo de código!

Enviando una Notificación a un Live Tile Pequeño

Vamos a empezar con enviar una notificación de tile pequeña primero, dado que los tiles largos serán un poco más complejos. Primero, como discutimos al principio, necesitas decidir que plantilla quieres usar del catálogo. (He creado una versión en PDF estática del documento para ti, ¡Así de importante será!)

En éste ejemplo, he elegido TileSquareText04, que se ve como esta plantilla:

clip_image013

Y es representado por este XML (sabría esto si abrieras la página del catálogo):

<tile>

<visual>

<binding template=”TileSquareText04″>

<text id=”1″>Text Field 1</text>

</binding>

</visual>

</tile>

Entonces ahora sólo necesitamos crear una nueva actualización de tile basado en ese XML, y la empujamos al TileUpdateManager. Así es como funciona para el TileSquareText04:

Como puedes ver en los comentarios del código, es un proceso bastante simple. Notaras que usamos notación de arreglo para establecer el valor del texto de la plantilla del tile. Esto es porque podemos tener más de un nodo de cada tipo. Si usáramos TileSquareBlock en su lugar, se vería como sigue:

clip_image014

Tendríamos dos valores de texto que actualizar, que sería algo así:

Una nota final acerca de estas plantillas es que es común que tu archivo SmallLogo.png se mostrará en algunos de estos tiles también. Es una buena forma de extender tu marca, pero es algo también que hay que tener presente al estar trabajando en esto. Al usar la plantilla TileSquareBlock, aquí tienes como mi tile se ve al final:

clip_image015

Esta es otra razón más, como lo dije en Día #1, para que uses imágenes personalizadas para tu app mientras exploras el desarrollo de Windows 8. Sin esa imagen morada, tendría que estarme preguntando cual estaba siendo usada, o peor, no darme cuenta que si quiera estuviera disponible. Verás que hay varias propiedades que pueden ser editadas para tu tile en el archivo Package.appxmanifest de tu proyecto. No solo puedes cambiar la imagen de logo, sino también las propiedades del fono, el archivo de logo pequeño, y otros valores de texto y color.

clip_image016

Una pieza importante de esta sección es el menú desplegable “Show name” o “Mostrar nombre”.

Mencione esto brevemente antes, pero quiero asegurarme de que entiendes donde se establecen estos valores e imágenes. Adicionalmente, simplemente definiendo un archivo de Wide logo en el manifiesto, inmediatamente soportas el tamaño Large Tile. Tu aplicación ni siquiera ofrecerá el tamaño como una opción hasta que hayas especificado ese valor. Inténtalo tú mismo. Ahora vamos a ver como enviar actualizaciones a un Tile Largo.

Enviando una Notificación a un Live Tile Largo

Esta vez, vamos a elegir una plantilla de Tile Largo, pero también incluir una imagen, para que puedas ver la sintaxis para esto también.

Lección Importante: Recuerda que el usuario está en control aquí. Si han decidido hacer tu tile largo o pequeño, no puedes controlarlo. Lo que si puedes controlar, sin embargo, es si quieres o no soportar “notificaciones” de ambos tamaños. Yo lo recomiendo, porque es una oportunidad de hacer que tu usuario ponga atención a tu app en su pantalla de Inicio.

Debido a esto, cuando enviamos actualizaciones, de hecho podemos crear dos. Una para el tile pequeño, y una para el largo. Entonces, a través de la magia de XML, vamos a juntarlos, y enviarlo como una sola notificación. Aquí está como se vería tu código:

//Crear el Tile Largo exactamente de la misma forma.

XmlDocument largeTileData = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWidePeekImage01);

XmlNodeList largeTextData = largeTileData.GetElementsByTagName(“text”);

XmlNodeList imageData = largeTileData.GetElementsByTagName(“image”);

largeTextData[0].InnerText = “Funny cat”;

largeTextData[1].InnerText = “This cat looks like it’s trying to eat your face.”;

((XmlElement)imageData[0]).SetAttribute(“src”, “ms-appx:///Assets/9-XAML-CatImage.png”);

//((XmlElement)imageData[0]).SetAttribute(“src”, “http://jeffblankenburg.com/downloads/9-XAML-CatImage.png”);

//Crear una notificación de Tile Pequeño también (no requerido, pero recomendado.)

XmlDocument smallTileData = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquarePeekImageAndText02);

XmlNodeList smallTileText = smallTileData.GetElementsByTagName(“text”);

XmlNodeList smallTileImage = smallTileData.GetElementsByTagName(“image”);

smallTileText[0].InnerText = “Funny cat”;

smallTileText[1].InnerText = “This cat looks like it’s trying to eat your face.”;

((XmlElement)smallTileImage[0]).SetAttribute(“src”, “ms-appx:///Assets/9-XAML-CatImageSmall.png”);

//Junta las dos actualizaciones en un nodo XML <visual>

IXmlNode newNode = largeTileData.ImportNode(smallTileData.GetElementsByTagName(“binding”).Item(0), true);

largeTileData.GetElementsByTagName(“visual”).Item(0).AppendChild(newNode);

//Crear las notificaciones de la misma forma.

TileNotification notification = new TileNotification(largeTileData);

notification.ExpirationTime = DateTimeOffset.UtcNow.AddSeconds(30);

//Empujar la actualización al tile.

TileUpdateManager.CreateTileUpdaterForApplication().Update(notification);

Lo deje ahí comentado, pero puedes ver que adicionalmente a empujar imágenes de tu proyecto local, también tienes la habilidad de usar imágenes que son hospedadas en la web. Toman mucho más tiempo en cargar, así que ten en mente eso cuando las uses.

Por ejemplo, puse la expiración de mi notificación a 30 segundos, y para el final de los 30 segundos, la notificación no había sucedido aun porque la imagen aún no ha llegado a mostrarse. Tu medida puede variar, pero usando imágenes locales, las notificaciones aparecen inmediatamente.

Aquí hay un video corto de esta actualización de Live Tile en acción en mi pantalla de Inicio:

http://www.youtube.com/watch?feature=player_embedded&v=EF1lvVbBeeQ

También, mencione que juntando dos archivos XML diferentes, una por cada plantilla. Aquí está la plantilla pequeña, para el TileSquarePeekImageAndText02:

<tile>

<visual>

<binding template=”TileSquarePeekImageAndText02″>

<image id=”1″ src=”image1″ alt=”alt text”/>

<text id=”1″>Text Header Field 1</text>

<text id=”2″>Text Field 2</text>

</binding>

</visual>

</tile>

Y aquí el XML para el tile Largo:

<tile>

<visual>

<binding template=”TileWidePeekImage01″>

<image id=”1″ src=”image1.png” alt=”alt text”/>

<text id=”1″>Text Header Field 1</text>

<text id=”2″>Text Field 2</text>

</binding>

</visual>

</tile>

Cuando se juntan, se ve así:

<tile>

<visual>

<binding template=”TileWidePeekImage01″>

<image id=”1″ src=”image1.png” alt=”alt text”/>

<text id=”1″>Text Header Field 1</text>

<text id=”2″>Text Field 2</text>

</binding>

<binding template=”TileSquarePeekImageAndText02″>

<image id=”1″ src=”image1″ alt=”alt text”/>

<text id=”1″>Text Header Field 1</text>

<text id=”2″>Text Field 2</text>

</binding>

</visual>

</tile>

Como puedes ver, terminamos con múltiples binding en un nodo <visual>. Para agregar notificaciones adicionales, pasarías por el mismo proceso, agregando aún más al mismo código.

Eliminando Tus Notificaciones

También habrá tiempos donde vas a querer borrar tus notificaciones. Tal vez nueva información está disponible, o algo cambio antes de que tus fechas de expiración caducaran, y necesitas iniciar de nuevo. Para hacer esto, es una simple línea de código:

TileUpdateManager.CreateTileUpdaterForApplication().Clear();

Entonces, hemos cubierto tiles largos y pequeños, incluso combinándolos, pero ¿Qué si quieres proveer a tu usuario con múltiples tiles?

Tiles Secundarios

Los tiles secundarios son una excelente forma de resaltar la información que tus usuarios quieren directamente en la pantalla de Inicio. Si eres una aplicación de clima, pueden anclar múltiples ciudades para una referencia rápida. Si eres la app de People, me permites anclar la gente que es importante para mí, así puedo ver fácilmente en que andan.

Originalmente pretendía escribir una sección entera aquí acerca de cómo anclar un Tile Secundario en la pantalla de inicio de tu usuario, pero Microsoft ha hecho un trabajo fenomenal al respecto. Chécalo aquí:

Inicio rápido: Anclaje de Tiles Secundarios

No solo te guían a través de crear un Tile Secundario, pero también te dan todo el código para preguntar al usuario desde una AppBar, determinar si ya la ha anclado, e incluso eliminar el tile cuando ya no es necesario. Es un gran tutorial, y lo recomiendo altamente.

Resumen

Hemos cubierto una gran cantidad de contenido hoy relacionado a las actualizaciones de Live Tiles de Windows 8. Desde la creación hasta la actualización, puedes ver que es bastante simple de hacer en tu app. No me canso de recomendarte actualizar los tiles de tu app con información relevante tan frecuentemente como sea posible. Esto hará tu app mucho más atractiva al usuario.

Para descargar la solución completa de código ejemplo para este artículo, haz click en el icono de abajo:

clip_image017

Mañana, vamos a ver el otro lado de las notificaciones: mensajes Toast. Hasta entonces, feliz codeo, ¡Y nos vemos mañana!

clip_image018

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 8: Información local e itinerante

March 17th, 2013 No comments

Esta artículo es una traducción de “Día 8: Información local e itinerante” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

En muchos artículos de esta serie hemos mencionado que almacenar información no solo es increíblemente importante sino también es super sencillo hacerlo de ambas maneras localmente en el dispositivo así como de manera itinerante (roaming) entre múltiples dispositivos que un usuario puede utilizar.

Microsoft nos ofrece algunas guías específicas de cuando utilizar almacenamiento por roaming y local, pero te daré un resumen rápido  aquí para que tengas la oportunidad de leerlo (porque ambos sabemos que no diste clic en este link). De nuevo, estas son guías, por lo que no estarás rechazado de la tienda por romper estas reglas pero también hay límites al tamaño de transferencia y velocidad. Al exceder estos límites evitará que tu aplicación permanezca enviando información por un largo periodo de tiempo.

Hacer

Usa roaming para preferencias y personalización. Cualquier opción en la que el usuario probablemente deba hacerla en cada máquina que utilice. Estas son configuraciones básicas como preferencias de color, actores favoritos o si publicar o no información vía Twitter.

Usa roaming para permitir a los usuarios continuar con una tarea. Tener los favoritos de mi explorador siguendome o incluso mis más altos resultados de un videojuego es maravilloso. Permitirme continuar escribiendo ese correo (o post) que nunca terminé. Mucho mejor.

No hacer

Usar roaming para información que es claramente solo local. Esto incluye cosas como rutas de archivos y cualquier otra información que solo tiene sentido en un dispositivo.

No envíes grandes cantidades de información. Hay un límite el cual puedes determinar en código, esto limitará el tamaño de tu envío de datos. Es mejor solo enviar preferencias y poca información como lo mostraremos en este artículo.

No uses roaming para sincronizaciones instantáneas o información que pueda cambiar rápidamente. Windows controla cuando y que tan seguido la información de tu aplicación será enviada, así que no debes contar con una sincronización instantánea. Crea un servicio web para ti mismo si necesitas este tipo de confiabilidad. También, no actualices la información de roaming constantemente. Por ejemplo, no necesitas almacenar de esta manera la ubicación de tu usuario en todo momento, en su lugar actualiza cada minuto o algo así. Aún tendrás la posibilidad de dar una experiencia buena sin destruir tu transferencia.

Una última cosa para recordar: La forma en la que tu información es enviada entre dispositivos es administra por la cuenta de usuario de Microsoft. Si ellos ingresan en dos máquinas con las mismas credenciales e instalan la misma aplicación en dos lugares ENTONCES las configuraciones de roaming y archivos viajarán. Hasta entonces, nada pasará.

Ahora que ya te he espantado en nunca usar esto, vamos a ver como se hace. Hay dos tipos de información que puede ser almacenada y nosotros manejaremos cada una de ellas localmente y vía roaming. Primero ajustemos la configuración seguida por archivos.

Ajustes locales y de roaming

Cuando escuchas la palabra “ajustes” en el desarrollo de Windows 8 (o incluso en Windows Phone), lo que te viene a la mente es “información simple y pequeña” y lo que realmente estamos diciendo es almacenar pares de nombres y valores.

Buenos ejemplos de esto son las preferencias del usuario. Quizá almacenaste el nombre del usuario (un valor de tipo cadena) de modo que podrías utilizarlo en algo como un juego. Quizá ellos decidieron inhabilitar las notificaciones (un valor booleano) de tu aplicación. Los ajustes son también una de las maneras más fáciles de almacenar información y me he encontrado a mi mismo en más de una ocasión almacenando un gran número de ajustes en mis aplicaciones. Dado que estos valores son invisibles y viven en un espacio de almacenamiento invisible, he cambiado un conjunto de métodos juntos que crearán, después leerán y por último eliminarán los valores de ajustes, ambos, locales y de roaming. Verás que es muy sencillo de usar.

ApplicationDataContainer settingsLocal;
ApplicationDataContainer settingsRoaming;
string currentBook;
int currentPage;

public MainPage()
{
this.InitializeComponent();

settingsLocal = ApplicationData.Current.LocalSettings;
settingsRoaming = ApplicationData.Current.RoamingSettings;

AddSettings();
}

ApplicationDataContainer ajustesLocales;
ApplicationDataContainer ajustesRoaming;
string libroActual;
int paginaActual;

public MainPage()
{
this.InitializeComponent();

ajustesLocales = ApplicationData.Current.LocalSettings;
ajustesRoaming = ApplicationData.Current.RoamingSettings;

AgregarConfiguracion();
}

private void AgregarConfiguracion()
{
ajustesLocales.Values["libroActual"] = "Secreto 1910";
ajustesLocales.Values["paginaActual"] = 33;

ajustesRoaming.Values["libroActual"] = "Secreto 1910";
ajustesRoaming.Values["paginaActual"] = 33;

LeerConfiguracion();
}

private void LeerConfiguracion()
{
libroActual = (string)ajustesLocales.Values["libroActual"];
paginaActual = (int)ajustesRoaming.Values["paginaActual"];

BorrarConfiguracion();
}

private void BorrarConfiguracion()
{
ajustesLocales.Values.Remove("libroActual");
ajustesLocales.Values.Remove("paginaActual");

ajustesRoaming.Values.Remove("libroActual");
ajustesRoaming.Values.Remove("paginaActual");
}

En este proyecto de ejemplo puedes establecer puntos de interrupción en cada método y después usar Visual Studio para inspeccionar nuestros valores de configuración en la tabla “Locals”.

Aquí esta como luce mi información después de que el método AgregarConfiguracion() se ha ejecutado.

image

Ahora, he leído la información de los ajustes y los he almacenado en valores en mi página.

image

Finalmente, después de que mi método para borrar los ajustes se ha ejecutado.

image

Mientras estás creando tus aplicaciones, es importante recordar que toda esta información, tanto ajustes como archivos, se encuentran dentro de una caja de arena de tu aplicación. Lo que significa es que cuando tu aplicación se desinstale, todos estos valores se irán con ella. Esto también significa que estás creando una aplicación que utiliza estos valores y quieres comenzar con una experiencia de usuario greenfield, quizá quieres desinstalar la aplicación antes de probarlo para evitar cualquier valor legado que haya sido guardado anteriormente.

Además de salvar estos pares de valor/nombre quizá quiere categorizarlos un poco. Podemos crear categorías de ajustes, lo cual hará que agregar y remover grupos de ajustes una tarea muy simple por hacer. Esto puede también obviamente ser hecho localmente y por roaming. Aquí esta una vista de crear una categoría y agregar un ajuste a ello.

settingsLocal.CreateContainer("mediaSettings", ApplicationDataCreateDisposition.Always);
settingsLocal.Containers["mediaSettings"].Values["Volume"] = 11;

Hasta aquí hemos llegado con la revisión profunda de los ajustes, vamos a movernos ahora a los archivos.

Archivos locales y vía roaming

Los archivos operan en una forma muy similar a los ajustes, excepto que estamos leyendo y escribiendo los valores al disco duro y demostraré eso en este ejemplo también. He colocado un conjunto idéntico de métodos a los que usamos en la sección de ajustes; un método AgregarArchivo(), LeerArchivo() y EliminarArchivo(). Aquí está un vistazo al código.

StorageFolder folderLocal;
StorageFolder folderRoaming;
string nombreArchivo = "tacotext.txt";
string contenidoArchivo = "taco";

public MainPage()
{
this.InitializeComponent();

folderLocal = ApplicationData.Current.LocalFolder;
folderRoaming = ApplicationData.Current.RoamingFolder;

AgregarArchivo();
}

private async void AgregarArchivo()
{
StorageFile archivoLocal = await folderLocal.CreateFileAsync(nombreArchivo, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(archivoLocal, contenidoArchivo + "taco");

LeerArchivo();
}

private async void LeerArchivo()
{
StorageFile archivoLocal = await folderLocal.GetFileAsync(nombreArchivo);
string textoLocal = await FileIO.ReadTextAsync(archivoLocal);

contenidoArchivo = textoLocal;

BorrarArchivo();
}

private async void BorrarArchivo()
{
StorageFile archivoLocal = await folderLocal.GetFileAsync(nombreArchivo);
await archivoLocal.DeleteAsync();
}

Como puedes ver la única gran diferencia es que ahora tenemos async/await en nuestros métodos que se encargan de leer el disco duro. No tenemos que especificar las ubicaciones de carpeta, ni siquiera tenemos que definir una estructura de carpetas si no queremos.

Además, puedes ver en tus archivos que estos se han guardado. Cada aplicación almacena sus archivos localmente en la máquina y si usas un pinto de interrupción puedes determinad la ubicación en tu dispositivo. Por ejemplo, el archivo “tacotext.txt” que he creado esta almacenado en la propiedad Path mostrada abajo.

image

Una vez que has lo has creado puedes incluso llegar al folder, abrirlo y ver el contenido, incluso puedes abrir el archivo por ti mismo.

8-XAML-FileLocation

¡Eso es todo! Guardar archivos, incluso archivos grandes puede ser hecho de esta manera. Solo necesitas recordar el nombre del archivo que le diste. La caja de arena de Windows 8 se encargará del resto.  Por favor nota que mi ejemplo arriba solo almacena un archivo local pero puedes usar el MISMO código (pero con la referencia a ApplicationData.Current.RoamingFolder en su lugar) para los archivos vía roaming.

Como recordatorio, los archivos vía roaming no se transferirán inmediatamente así que no esperes el tipo de rendimiento que has visto con las aplicaciones como SkyDrive o DropBox. Se cauteloso del la transferencia de información pero de cualquier manera, usa esto mucho.

En resumen

Los ajustes y configuraciones son una herramienta poderosa en el arsenal de desarrollo de Windows 8. Es fácil de hacer y hacer a tu aplicación mucho más genial cuando es capaz de trabajar con diferentes dispositivos a la vez. Yo aún cuento historias acerca de la primera vez que jugué Jetpack Joyride en una segunda máquina y todas mis compras, jetpacks, equipo y ajustes se mostraron de inmediato. Hizo lo que ya era un juego increíble algo mucho mejor para mí. Por esto recomiendo que lo hagas por ti mismo. (Es un juego gratuito pero hay una opción de in-app purchasing por $1.49 USD para duplicar tus monedas por cada nivel completado. Lo vale totalmente).

8-XAML-JetpackJoyride

Para descargar el código de ejemplo de este artículo da clic en el ícono de abajo.

 

 

Mañana, vamos a discutir acerca de los mosaicos activos (Live Tiles) y como crear ambos, tanto los primarios como secundarios así como actualizarlos. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 7: El contrato para compartir

March 16th, 2013 No comments

Esta artículo es una traducción de “Día 7: El contrato para compartir” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Los dos últimos días hemos trabajado con un nuevo elemento en Windows 8: Los contratos. Presentamos esta noción de contratos al explorar como incorporar ajustes a nuestras aplicaciones. Entonces exploramos como extender la presencia de nuestras aplicaciones a los usuarios mediante la búsqueda. Hoy vamos a tomar el siguiente paso y explorar uno de los elementos que más nos emociona. Compartir.

Antes de Windows 8, crear una aplicación “social” era complicado. No solo porque tuvieras que aprender bastantes APIs de las plataformas con las que quisieras trabajar sino también tenías que conocer el API para Facebook, Twitter y cualquier otra red social que quisieras incluir.

Eso era demasiado abrumador sino es que caía en lo imposible de realizar efectivamente.

Con Windows 8, solo nos debemos preocupar por crear nuestra aplicación. De hecho, colocar botones en tu aplicación que digan “Compartir en X red social” ya es desaprobado en este sistema. ¿Por qué darle al usuario un botón de Twitter cuando no usan Twitter? Lo mismo para Google+, Facebook, Flickr, GitHub o cualquier otra plataforma basada en modo social.

Con el contrato de Compartir, el usuario se encuentra en total control.Tu haces tu contenido compartible y ELLOS deciden donde y como compartirlo. Es un sentimiento de control que es verdaderamente unos de los mejores elementos de Windows 8 para mí.

Definir lo compartido

Compartir sucede en dos formas, quien comparte (la aplicación origen) y quien recibe (la aplicación destino). Esto sucede por medio de un corredor.

Block diagram showng the components involved in sharing

Imagen vía: http://msdn.microsoft.com/en-us/library/windows/apps/hh758314.aspx

¿Qué tipo de archivos puedes compartir? Hay 6 diferentes tipos de contenido que puedes compartir con el corredor:

* Texto plano sin formato

* Enlaces

* Contenido con formato / HTML

* Archivos

* Una imagen sencilla

* Un formato de información personalizado

La información es compartida por medio de un objeto llamado DataPackage- En este artículo vamos a dividir el compartir origen y el compartir destino en dos secciones separadas.

Compartir Origen

Vamos a comenzar con el más simple de dos escenarios.  El origen para compartir. En este escenario vamos a mostrar como puedes compartir cada uno de los siete tipos de contenidos mostrados arriba. Primero, necesitamos  crear una nueva solución en blanco para comenzar desde ahí. En el código de ejemplo para este artículo notarás que he creado una página separada para cada tipo de información. Ciertamente no necesitas hacerlo en tu aplicación pero ten en cuenta que puedes solo compartir un tipo de información a la vez desde cualquier página. Vamos a comenzar con el texto sin formato.

El plan de compartir para el texto sin formato

Este será el ejemplo más largo para el código de compartir porque la mayoría del código es exactamente el mismo para cada ejemplo. Solo voy a resaltar lo necesario y después me enfocaré en los elementos que son diferentes en los ejemplos sucesivos.

Primero necesitamos crear una referencia al DataTransferManager. Necesitarás agregar el espacio de nombres Windows.ApplicationModel.DataTransfer a tu página. En el código debajo verás que instancío la referencia al DataTransferManager y después creo un manejador de eventos (en el método OnNavigated()) para cuando la información sea solicitada para ser compartida desde este página con el manejador de eventos DataRequest().

DataTransferManager dtm;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
dtm = DataTransferManager.GetForCurrentView();
dtm.DataRequested += dtm_DataRequested;
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
dtm.DataRequested -= dtm_DataRequested;
}

Deberás también notar que ajustamos el método OnNavigatedFrom para retirar el manejador de DataRequested cuando dejamos la página. Esta es una buena práctica que deberías incorporar en cada una de tus páginas. Asegúrate de cancelar cualquier manejador de eventos que estás registrando.

Finalmente, necesitamos compartir algo de texto y hacemos esto por medio de nuestro método dtm_DataRequested().

void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
string tituloFiltro = "31 días de Windows 8";
string DescripcionArchivo = "Esto solo explica lo que estamos compartiendo";

DataPackage informacion = args.Request.Data;
informacion.Properties.Title = tituloFiltro;
informacion.Properties.Description = DescripcionArchivo;
informacion.SetText("Probando la funcionalidad en Windows 8");
}

Como puedes ver simplemente creamos un objeto DataPacker y ajustamos sus propiedades de manera acordada. Usando los valores que he puesto en el código aquí está el mensaje que el usuario verá.

image

Una vez que hayas seleccionado una aplicación (en este caso la del correo), verán que la información llena la aplicación elegida:

image

Para el resto de los tipos de información te mostraré los contenidos del método dtm_DataRequest() pero todo lo demás se resume básicamente de la misma forma.

Compartir enlaces

La única diferencia entre un enlace y el texto sin formato es que debes especificar un objeto de tipo Uri al DataPackage. Aquí está el código.

void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
Uri fuenteLink = new Uri("http://aminespinoza.com/");
string tituloFiltro = "31 días de Windows 8";
string DescripcionArchivo = "Esto solo explica lo que estamos compartiendo";

DataPackage data = args.Request.Data;
data.Properties.Title = tituloFiltro;
data.Properties.Description = DescripcionArchivo;
data.SetUri(fuenteLink);
}

La principal diferencia está en la UI. Aquí está el mensaje inicial para compartir.

image

Notarás que tienes la posibilidad de colocarlo no solo como correo. Si abrierara la aplicación de Contactos tendría la facilidad de elegir entre Facebook y Twitter. Aquí está lo que la aplicación de correo hará con la información una vez abierta.

image

Lo genial de esta implementación son unos cuantos elementos:

La aplicación de correo ha navegado en la web y obtenido un par de imágenes que podrían ser útiles como muestra.

La aplicación de correo también obtuvo el título del sitio web y lo usó en el listado. Muy útil.

En el ejemplo del texto sin formato, la propiedad Descripcion no fue utilizada en la aplicación de correo. En este caso fue incrustada en el enlace.

Vamos a pasar ahora a la manera de compartir contenido con formato como HTML.

Compartiendo Contenido con formato / HTML

Aquí está una vista de nuestra implementación de código.

void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
string cadenaHTML = "<strong>Texto resaltado,</strong> texto normal.  <a href='http://blogs.ligasilverlight.com/blog/'>Checa nuestros 31 días con Windows 8</a>";
string tituloHTML = "31 Días de Windows 8";
string DescripcionHTML = "Esto solo explica lo que estamos compartiendo";

DataPackage informacion = args.Request.Data;
informacion.Properties.Title = tituloHTML;
informacion.Properties.Description = DescripcionHTML;
informacion.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat(cadenaHTML));
}

Tuvimos que tratar este contenido de una manera ligeramente diferentes. Notarás que cuando mandamos nuestro contenido desde nuestro DataPackage en esta ocasión tuvimos que llamar al elemento HtmlFormat. Esto tomará a nuestra cadena ordinaria y la convertirá en un conjunto HTML activo que puede ser colocado y utilizado. El mensaje inicial luce exactamente de la misma forma pero puedes ver el contenido HTML con formato aparece en el cuerpo de nuestro mensaje de correo.

image

image

Una grana plicación de esto podría ser crear mensajes de correo con contenido HTML. Crear mensajes de este tipo es extremadamente difícil para aquellos que no conocen HTML. Imagina una aplicación simple que permita crear una interfaz visualmente de HTML y después puedan compartirla a su lista de clientes y enviarla. Alguien hizo esto.

Compartir archivos

Uno o más archivos son tratados de la misma manera que en esta situación pero dado que estamos leyendo archivos desde el almacenamiento hay un poco más de código necesario para ser escrito. Si tienes archivos adicionales encontrarás y agregarás simplemente  la lógica asíncrona necesaria, y después los agregarás a una colección de tipo List<IStorageItem> Asíncronamente vamos a obtener los archivos y cuando la operación esté completada, los compartiremos.

async void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
string tituloHTML = "31 Días de Windows 8";
string DescripcionHTML = "Esto solo explica lo que estamos compartiendo";

DataPackage informacion = args.Request.Data;
informacion.Properties.Title = tituloHTML;
informacion.Properties.Description = DescripcionHTML;

DataRequestDeferral waiter = args.Request.GetDeferral();

try
{
StorageFile archivoDeTexto = await Package.Current.InstalledLocation.GetFileAsync("ArchivoCompartir.txt");
List<istorageitem> archivos = new List</istorageitem><istorageitem>();
archivos.Add(archivoDeTexto);
informacion.SetStorageItems(archivos);

}
finally
{
waiter.Complete();
}
}

Nota que el método entero necesitó ser decorado con la palabra reservada “async” para poder hacer que todo funcione. Veras esto muchas veces en el desarrollo de Windows 8 y es la manera de lidiar con eventos asíncronos. Simplemente te hace la vida mucho más simple. Si no es esta enteramente claro, cree un archivo de texto simple y lo agregué en mi proyecto. Este es el archivo que tomaré y compartiré. De nuevo, el mensaje de compartir lucirá idéntico la primera vez pero cuando abres la aplicación de correo lucirá abierto de la siguiente manera.

image

La parte interesante a notar en esta situación es que la aplicación de correo previamente utilizó nuestro título como tema del mensaje del correo. En este ejemplo no lo hace. Estoy seguro que el equipo de producto tiene una razón por la cual esto sucede pero yo votaría por consistencia en esto.

Compartir imágenes

Cuando compartes un archivo de imagen quizá quieres tratarlo diferente a un solo archivo básico o quizá no. En este ejemplo, vamos a compartir nuestro archivo de imagen de dos maneras diferentes de modo que las aplicaciones objetivo puedan usar la información en la que están interesadas. Las aplicaciones que buscan por archivos estarán disponibles tanto como las aplicaciones que buscan por imágenes específicamente. Puedes usar este útil truco cuando has tenido múltiples tipos de información para compartir también, no solo cuando la misma cosa puede ser compartida de dos maneras diferentes.

async void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
string tituloHTML = "31 Días de Windows 8";
string DescripcionHTML = "Esto solo explica lo que estamos compartiendo";

DataPackage informacion = args.Request.Data;
informacion.Properties.Title = tituloHTML;
informacion.Properties.Description = DescripcionHTML;

DataRequestDeferral waiter = args.Request.GetDeferral();

try
{
StorageFile imagen = await Package.Current.InstalledLocation.GetFileAsync("Assets\\Logo.png");
informacion.Properties.Thumbnail = RandomAccessStreamReference.CreateFromFile(imagen);
informacion.SetBitmap(RandomAccessStreamReference.CreateFromFile(imagen));

List</istorageitem><istorageitem> archivos = new List</istorageitem><istorageitem>();
archivos.Add(imagen);
informacion.SetStorageItems(archivos);
}
finally
{
waiter.Complete();
}
}

Puedes ver que hemos la llamado ambos métodos SetBitmap así como al método SetStorageItems. En cualquier caso el mensaje de compartir lucirá idéntico. Por ejemplo, la aplicación de correo no permite imágenes “crudas” pero si las acepta como StorageItems. Dale a este código de ejemplo un intento. Estaba también sorprendido de ver que la aplicación de contacto no acepta ningún tipo de compartir.  Hablaremos más tarde en este artículo acerca de ser una aplicación objeto para compartir y como podemos aceptar diferentes tipos de información.

Compartiendo un formato personalizado de información

Hay muchas veces en las que vas a querer compartir algún tupo de información personalizada. En el 99% de las ocasiones, para hacerlo debes caer en un esquema estándar como los que puedes encontrar en http://schema.org. De hecho no estás bloqueado en un esquema predeterminado pero asegúrate de que entiendes la guía que Microsoft ofrece para crear tus tipos de información personalizados.

La historia pequeña acerca de compartir información personalizada es que vas a especificar un DataPackageFormat pero puede ser absolutamente lo que tu quieras. Para la mayoría de propósitos solo podrás compartir información personalizada entre dos de tus propias aplicaciones pero estandarizando en un esquema estándar ciertamente incrementa las posibilidades de compartir con otras aplicaciones también. Al final tu especificarás una cadena que represente el esquema de tu información y si otra aplicación es un objeto para el mismo y específico tipo de caracteres de la cadena entonces se mostrarán en la lista de aplicaciones potenciales.

void dtm_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
string informacionPersonalizada = @"{
""type"" : ""http://schema.org/Person"",
""properties"" :
{
""image"" : ""http://jeffblankenburg.com/images/200x200.png"",
""name"" : ""Jeff Blankenburg"",
""affiliation"" : ""Microsoft"",
""birthDate"" : ""07/22/1976"",
""jobTitle"" : ""Senior Technical Evangelist"",
""nationality"" : ""United States of America"",
""gender"" : ""Male""
}
}";
string tituloCompartir = "31 Days of Windows 8!";
string enlaceDescripcion = "This just explains what we're sharing.";  //This is an optional value.

DataPackage informacion = args.Request.Data;
informacion.Properties.Title = tituloCompartir;
informacion.Properties.Description = enlaceDescripcion;
informacion.SetData("http://schema.org/Person", informacionPersonalizada);
}

En el ejemplo de arriba estoy usando el esquema de http://schema.org/Person y dado que ninguna de mis otras aplicaciones en mi máquina reconocen este esquema obtendré un mensaje al momento de compartir como el siguiente.

7-XAML-CustomDataPrompt

Como has visto a lo largo de esta sección, nuestro título y descripción continúan mostrándose en el mismo lugar pero esta ocasión no hay ninguna app disponible para compartir. En la siguiente sección, vamos a ver como hacer que nuestra aplicación sea capaz de recibir estos tipos de datos.

Objetivo para compartir

Cuando me senté por primera vez a escribir este artículo hice a esta parte la última porque pensé que sería mucho más difícil (y largo) que la otra. Ahora que lo veo, estoy equivocado. Mucho del trabajo para ser una aplicación para compartir cae en tu archivo Package.appmanifest.

Abre el tuyo en la sección de Declaraciones y será probable que encuentres una tierra estéril. Lo que necesitamos hacer es agregar la declaración de Share Target al elegir de la caja de elecciones y presiona el botón de Agregar.

7-XAML-AppManifest

Una vez que has agregado la opción de compartir, se comenzarán a mostrar muchos signos rojos de advertencia.

7-XAML-AppManifestBroken

Agregar una declaración para compartir no es suficiente. También necesitas especificar que tipo de archivo va a recibir. Afortunadamente podemos elegir cualquiera o todos los formatos que hemos cubierto en este artículo. La siguiente imagen muestra mis declaraciones completamente llenas haciendo mi aplicación un objeto para casi todo.

7-XAML-AppManifestComplete

Ahora como nos metemos en el código, hay un largo camino aquí que probablemente necesitas para tu aplicación. He creado un ejemplo que comparte y consume cada posible tipo de información y como tal tiene muchas más líneas de código que las que quisieras.

Primero, necesitamos abrir nuestro archivo App.xaml.cs y agregar un nuevo método para manejar cuando el compartir esté activado. Es sin sorpresa OnShareTargetActivated.

protected override void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
var rootFrame = new Frame();
rootFrame.Navigate(typeof(MainPage), args.ShareOperation;
Window.Current.Content = rootFrame;
Window.Current.Activate();
}

Todo esto realmente indica a la aplicación cual es la página que quieres mostrar una vez que tu aplicación ha sido seleccionada para compartir. Esto probablemente es una página separada para ti (no MainPage) pero para mi ejemplo, es exactamente la que he usado.

Ahora para el proceso largo de lógica. He agregado comentarios de modo que puedes encontrar las piezas en las que estés específicamente interesado. Ubica el método entero de OnNavigatedTo() en el ejemplo en MainPage.xaml.cs. Recuerda que esta lógica irá en una página separada en tu aplicación para poder delegar una sola responsabilidad de atrapar ciertos tipos de información compartida.

Podrás ver que cada ejemplo es ligeramente diferente dependiendo del tipo de información.

En resumen

Hoy, vimos un repaso muy extendido para agregar la opción de compartir en tu aplicación. El contrato para compartir te da un increíble nuevo paradigma de aplicaciones con las cuales interactuar. Es algo enormemente refrescanta acerca de saber que aplicaciones que no tienen idea que la mía existe puedan aún comunicarse entre ellas. Espero que tomes esta oportunidad para compartir y consumir la información que sea útil en tu aplicación.

Puedes descargar el ejemplo entero de este artículo desde aquí.

 

 

Mañana, vamos a enfocarnos en almacenar información de ambas maneras, localmente en el dispositivo así como información en la nube ¡Nos vemos!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 6: El contrato de búsqueda

March 7th, 2013 No comments

Este artículo es una traducción de “Día 6: El contrato de búsqueda” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Ayer comenzamos a hablar de contratos al explorar como agregar ajustes a nuestras aplicaciones. Hoy vamos a trabajar sobre la búsqueda y mañana con compartir porque estas funciones le dan más vida a tu aplicación cunado no está ejecutándose precisamente. En el contexto de buscar, esto significa que tu aplicación puede potencialmente exponerse a sí misma al usuario en una nueva forma.

Por los últimos 10 años “buscar” ha sido típicamente sinónimo de los motores de búsqueda. Hace algunos años buscar se ha vuelto muy importante en Windows y si eras como yo te volviste muy hábil en presionar el botón de inicio y escribir el nombre del programa en lugar de ir por el. Hoy en Windows 8 puedes solo escribir y esos resultados serán desplegados de una manera agradable.

Mejor aún, Windows 8 esta realmente extendiendo la manera en como conocemos la búsqueda y la está trayendo justo a nuestras aplicaciones de Windows Store. Ahora no hay ninguna magia, solo atamos algunos eventos y desplegamos las cosas adecuadas a nuestros usuarios pero cambia el típico “punto de entrada” en nuestras aplicaciones. Ahora, en lugar de que nuestro usuario abra su aplicación, busque la caja de búsqueda y comience a buscar, podrá presionar buscar y ser llevado directamente a lo que ellos estuvieran buscando sin más pasos.

Comenzando a configurar

Como lo hemos hecho cada día desde el inicio de esta serie, vamos a comenzar  con la plantilla en blanco. De nuevo, la razón por la que hacemos esto es porque hay mucho código extra para filtrar antes de encontrar lo que estabas buscando.

Una vez que has tenido tu nuevo proyecto (y reemplazado la imagen por defecto… ¿Hiciste eso no? ¿No recuerdas el día 1?). Ahora vamos a agregar la búsqueda a nuestra aplicación. Afortunadamente la búsqueda básica esta a solo un clic de distancia.

Da clic derecho sobre tu proyecto y selecciona Agregar > Nuevo elemento > Search contract.

image

Te preguntará por el nombre de una página para trabajar con ella. Yo he usado ResultadosBusqueda.xaml pero puedes llamar a la página como desees

image

Vamos a discutir cada uno de estos archivos brevemente un poco después pero por ahora, deberías ver una solución que luzca como la siguiente.

image

Hasta aquí, deberías ser capaz de correr tu proyecto, elegir el botón de búsqueda y comenzar a escribir. Aquí está como luce mi aplicación cuando busco por “taco”.

image

Como puedes ver, funciona pero no estamos dándole ningún valor porque no tenemos nada para buscar. Esto viene después pero antes de ello vamos a hablar acerca de la filosofía detrás de la búsqueda en Windows 8.

Filosofía de búsqueda

Cuando piensas en una aplicación tradicional de Windows 8 estas son generalmente de menor tamaño. No encontrarás una versión de Outlook por ejemplo, que administre muchos tipos de información. En su lugar, hay una aplicación de calendario, una aplicación de correo y una aplicación de contactos.

Las aplicaciones Windows 8 están hechas para hacer una cosa y hacerla realmente bien. Afortunadamente estoy quizá describiendo la aplicación que estás creando ahora. Las aplicaciones Windows 8 pueden ser también buscadas incluso cuando no están corriendo. Eso quiere decir que cuando el usuario esta buscando por algo, el nombre de tu aplicación quizá muestre ciertos tipos de información.

Por ejemplo, la aplicación iHeartRadio. Si estoy buscándola quizá encontraré una estación de radio.

6-XAML-IHeartRadio

Para una aplicación de clima es como si buscara por una ciudad.

6-XAML-Weather

Netflix, quizá estoy buscando por el título de una película o show.

6-XAML-Netflix

Finalmente, la aplicación de Gente asume que estoy buscando por el nombre de una persona.

Así que como tu estas creando tu aplicación. Hazte a ti mismo una pregunta.

¿Que esperarían los usuarios buscar en mi aplicación?

Otra discusión importante acerca de la búsqueda revuelve el concepto de “Buscar” contra “Encontrar”. El botón de buscar NOT es usado para mirar dentro de un documento. Buscar siempre debe ser algo que puede ser hecho en tu aplicación incluso si no está ejecutándose.

Aquí hay una guía específica de Microsoft de como usar la el botón de Buscar.

Haciendo funcionar la búsqueda

Como vimos en nuestros párrafos de inicio, agregar el contrato de búsqueda a tu proyecto es solo el primer paso. Después necesitamos dar algo de información importante para que el usuario busque. Si vuelves a visitar el artículo del día 4, cree un conjunto pequeño de elementos de la tabla periódica para demostrar el control de Zoom Semántico.

Podremos usar la misma información en este ejemplo. En el caso de que lo hayas dejado pasar aquí tienes la clase Elemento.

class Elemento
{
public double AtomicWeight { get; set; }
public int AtomicNumber { get; set; }
public string Symbol { get; set; }
public string Name { get; set; }
public string Category { get; set; }
public string State { get; set; }
}

Por simplicidad, voy a poblar la una lista de tipo Elemento en nuestro archivo PaginaResultados.xaml.cs. Iniciaré creando un nuevo método, CrearListaElementos() y llamándolo desde nuestro constructor, después crearé un nuevo objeto de tipo Elemento para los 36 elementos que estaré usando.

private void CrearListaElementos()
{
elementos.Add(new Elemento { NumeroAtomico = 1, PesoAtomico = 1.01, Categoria = "Metales alcalinos", Nombre = "Hidrógeno", Simbolo = "H", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 2, PesoAtomico = 4.003, Categoria = "Gases nobles", Nombre = "Helio", Simbolo = "He", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 3, PesoAtomico = 6.94, Categoria = "Metales alcalinos", Nombre = "Litio", Simbolo = "Li", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 4, PesoAtomico = 9.01, Categoria = "Tierras alcalinas", Nombre = "Berilio", Simbolo = "Be", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 5, PesoAtomico = 10.81, Categoria = "No Metales", Nombre = "Boro", Simbolo = "B", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 6, PesoAtomico = 12.01, Categoria = "No Metales", Nombre = "Carbono", Simbolo = "C", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 7, PesoAtomico = 14.01, Categoria = "No Metales", Nombre = "Nitrogeno", Simbolo = "N", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 8, PesoAtomico = 15.999, Categoria = "No Metales", Nombre = "Oxígeno", Simbolo = "O", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 9, PesoAtomico = 18.998, Categoria = "No Metales", Nombre = "Flúor", Simbolo = "F", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 10, PesoAtomico = 20.18, Categoria = "Gases nobles", Nombre = "Neón", Simbolo = "Ne", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 11, PesoAtomico = 22.99, Categoria = "Metales alcalinos", Nombre = "Sodio", Simbolo = "Na", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 12, PesoAtomico = 24.31, Categoria = "Tierras alcalinas", Nombre = "Magnesio", Simbolo = "Mg", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 13, PesoAtomico = 26.98, Categoria = "Otros metales", Nombre = "Aluminio", Simbolo = "Al", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 14, PesoAtomico = 28.09, Categoria = "No Metales", Nombre = "Silicio", Simbolo = "Si", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 15, PesoAtomico = 30.97, Categoria = "No Metales", Nombre = "Fósforo", Simbolo = "P", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 16, PesoAtomico = 32.06, Categoria = "No Metales", Nombre = "Azufre", Simbolo = "S", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 17, PesoAtomico = 35.45, Categoria = "No Metales", Nombre = "Cloro", Simbolo = "Cl", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 18, PesoAtomico = 39.95, Categoria = "Gases nobles", Nombre = "Argón", Simbolo = "Ar", Estado = "Gas" });
elementos.Add(new Elemento { NumeroAtomico = 19, PesoAtomico = 39.10, Categoria = "Metales alcalinos", Nombre = "Potasio", Simbolo = "K", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 20, PesoAtomico = 40.08, Categoria = "Tierras alcalinas", Nombre = "Calcio", Simbolo = "Ca", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 21, PesoAtomico = 44.96, Categoria = "Metales de transición", Nombre = "Escandio", Simbolo = "Sc", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 22, PesoAtomico = 47.90, Categoria = "Metales de transición", Nombre = "Titanio", Simbolo = "Ti", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 23, PesoAtomico = 50.94, Categoria = "Metales de transición", Nombre = "Vanadio", Simbolo = "V", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 24, PesoAtomico = 51.996, Categoria = "Metales de transición", Nombre = "Cromo", Simbolo = "Cr", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 25, PesoAtomico = 54.94, Categoria = "Metales de transición", Nombre = "Manganeso", Simbolo = "Mn", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 26, PesoAtomico = 55.85, Categoria = "Metales de transición", Nombre = "Hierro", Simbolo = "Fe", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 27, PesoAtomico = 58.93, Categoria = "Metales de transición", Nombre = "Cobalto", Simbolo = "Co", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 28, PesoAtomico = 58.70, Categoria = "Metales de transición", Nombre = "Níquel", Simbolo = "Ni", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 29, PesoAtomico = 63.55, Categoria = "Metales de transición", Nombre = "Cobre", Simbolo = "Cu", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 30, PesoAtomico = 65.37, Categoria = "Metales de transición", Nombre = "Zinc", Simbolo = "Zn", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 31, PesoAtomico = 69.72, Categoria = "Otros metales", Nombre = "Galio", Simbolo = "Ga", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 32, PesoAtomico = 72.59, Categoria = "Otros metales", Nombre = "Germanio", Simbolo = "Ge", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 33, PesoAtomico = 74.92, Categoria = "No Metales", Nombre = "Arsénico", Simbolo = "As", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 34, PesoAtomico = 78.96, Categoria = "No Metales", Nombre = "Selenio", Simbolo = "Se", Estado = "Sólido" });
elementos.Add(new Elemento { NumeroAtomico = 35, PesoAtomico = 79.90, Categoria = "No Metales", Nombre = "Bromo", Simbolo = "Br", Estado = "Líquido" });
elementos.Add(new Elemento { NumeroAtomico = 36, PesoAtomico = 83.80, Categoria = "Gases nobles", Nombre = "Kryptón", Simbolo = "Kr", Estado = "Gas" });
}

Obviamente, vas a querer obtener tu información desde otra ubicación pero este artículo es acerca de búsqueda no de fuentes de datos.

Si miras en el método FilterSelectionChanged() que fue creado en PaginaResultados.xaml.cs verías algunos comentarios como el siguiente.

// TODO: Respond to the change in active filter by setting this.DefaultViewModel["Results"]
// to a collection of items with bindable Image, Title, Subtitle, and Description properties

Justo debajo de estos comentarios, vamos a agregar nuestra lógica para obtener los registros adecuados desde nuestra fuente de datos. Antes de que hagamos eso, sin embargo, hay muchas suposiciones a considerar por ti para este método y es importante entender que esas suposiciones están antes de que escribas cualquier otra cosa.

La primera suposición es que los resultados de tu búsqueda van a ser una colección de objetos que tengan una propiedad para imagen, título, subtitulo y descripción. Es improbable que tu información tenga esta información y no quieras forzarla a hacerlo para que se alinee a lo que te están pidiendo. La razón para esta suposición es muy simple.

Abre brevemente su página de PaginaResultados.xaml. Mira al control de tipo GridView llamado “resultsGridView” así como al control ListView llamado “resultasListVie”. Hemos ya cubierto estos tipos de controles en el Día 4 pero ellos tienen ahora un ItemTemplate ya definido. Aquí es donde viven todas las suposiciones. Están usando el DataTemplate por defecto llamado “StandardSmallIcon300x70ItemTemplate”. Si das un vistazo a tu archivo “Common/StandardStyles.xaml” lo encontrarás ahí y está tratando de enlazar aquellas cuatro propiedades que mencioné antes. No queremos usar esa plantilla, pero es un buen inicio.

Lo que he hecho es copiar esa DataTemplate completa y moverla a mi página PaginaResultados.xaml en la sección de recursos. Aquí está lo que he modificado de la sección.

<page .Resources>
<collectionviewsource x:Name="resultsViewSource" Source="{Binding Results}"></collectionviewsource>
<collectionviewsource x:Name="filtersViewSource" Source="{Binding Filters}"></collectionviewsource>
<common:booleantovisibilityconverter x:Key="BooleanToVisibilityConverter"></common:booleantovisibilityconverter>
<!-- TODO: Update the following string to be the name of your app -->
<x:string x:Key="AppName">App Name</x:string>
<datatemplate x:Key="ModifiedSmallIcon300x70ItemTemplate">
<grid Width="294" Margin="6">
</grid><grid .ColumnDefinitions>
<columndefinition Width="Auto"></columndefinition>
<columndefinition Width="*"></columndefinition>
</grid>
<border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,0,0,10" Width="40" Height="40">
<textblock Text="{Binding Symbol}" FontSize="32" FontWeight="Bold" TextAlignment="Center" VerticalAlignment="Center"></textblock>
</border>
<stackpanel Grid.Column="1" Margin="10,-10,0,0">
<textblock Text="{Binding Name}" Style="{StaticResource BodyTextStyle}" TextWrapping="NoWrap"></textblock>
<textblock Text="{Binding Category}" Style="{StaticResource BodyTextStyle}" Foreground="{StaticResource ApplicationSecondaryForegroundThemeBrush}" TextWrapping="NoWrap"></textblock>
<textblock Text="{Binding State}" Style="{StaticResource BodyTextStyle}" Foreground="{StaticResource ApplicationSecondaryForegroundThemeBrush}" TextWrapping="NoWrap"></textblock>
</stackpanel>

</datatemplate>
</page>

Puedes ver que es casi idéntico al original pero lo he renombrado a “ModifiedSmallIcon300x70ItemTemplate”. Las otras diferencias son quehe cambiado el control Imagen por otro TextBlock y cambiado los enlazados a las propiedades que mi objeto posee, Simbolo, Nombre,Categoria y Estado. He cambiado también el nombre de los ItemTemplates usados por el control GridView y ListView para apuntar a mi versión modificada también. Ahora podemos comenzar a dar algunos resultados a nuestra Página de Resultados.

¿Recuerdas esos controles desde antes? Los que estaban en el método Filter_SelectionChanged()? Vamos a volver a visitarlos y agregar algo de código.

IEnumerable<elemento> resultadosBusqueda = from el in elementos
where el.Nombre.ToLower().Contains(cadenaBusqueda)
orderby el.Nombre ascending
select el;

DefaultViewModel["Resultados"] = resultadosBusqueda;

object resultados;
IEnumerable</elemento><elemento> coleccionResultados;

if (DefaultViewModel.TryGetValue("Resultados", out resultados) &amp;amp;amp;&amp;amp;amp;
(coleccionResultados = resultados as IEnumerable</elemento><elemento>) != null &amp;amp;amp;&amp;amp;amp;
coleccionResultados.Count() != 0)
{
VisualStateManager.GoToState(this, "ResultsFound", true);
return;
}

He agregado una sentencia LINQ simple para obtener la información adecuada desde mi fuente de datos y asigné los resultados a this.DefaultViewModel[“Resultados”]. Esto es lo que llenará a nuestro control GridView.

También he modificado un poco del código por defecto en la sección de abajo para llamar explícitamente que estoy usando una lista IEnumerable de objetos de tipo Element. Si tu término de búsqueda tiene de hecho algunos resultados, esta lógica será la que muestre los resultados.

En este punto, si ejecutas tu proyecto y haces una búsqueda deberías obtener algo así como lo que se ve a continuación.

image

Puedes incluso cerrar la aplicación enteramente, ejecutar una búsqueda en tu máquina y después elegir tu aplicación. Trabaja exactamente de la misma forma.

Hasta aquí, habrás pensado que estamos listos. Bueno, estás equivocado. Tenemos mucho de que hablar aún. Específicamente que hará el usuario una vez que tenga los valores resultantes de acuerdo a lo que ellos han buscado. Vamos a ver lo siguiente.

Definir sugerencias de búsqueda

Este es un proceso muy simple de hecho, específicamente comparado con lo que hemos hecho en este artículo. En nuestra página PaginaResultados.xaml necesitamos iniciar con una referencia a la clase SearchPane (quizá también necesites agregar la referencia a Windows.ApplicationModel.Search). También iniciamos una instancia del objeto SerachPane in nuestro constructor.

SearchPane panelBusqueda;

public PaginaResultados()
{
this.InitializeComponent();
CrearListaElementos();
panelBusqueda = SearchPane.GetForCurrentView();
}

Una vez que lo hayas hecho, el siguiente paso es crear un manejador de eventos para el evento SuggestionsRequested. Crea un nuevo método OnNavigatedTo como el de abajo y agrega el nuevo manejador de eventos (también retíralo en el método OnNavigatedFrom).

protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
panelBusqueda.SuggestionsRequested += searchPane_SuggestionsRequested;
}

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
base.OnNavigatingFrom(e);
panelBusqueda.SuggestionsRequested -= searchPane_SuggestionsRequested;
}

void searchPane_SuggestionsRequested(SearchPane sender, SearchPaneSuggestionsRequestedEventArgs args)
{
args.Request.SearchSuggestionCollection.AppendQuerySuggestions((from el in elementos
where el.Nombre.ToLower().StartsWith(args.QueryText.ToLower()) || el.Simbolo.ToLower().StartsWith(args.QueryText.ToLower())
orderby el.Nombre ascending
select el.Nombre).Take(5));
}

Puedes ver que simplemente estoy dándole a la colección un conjunto de máximo cinco valores como recomendación. Esto es lo más que podrá mostrar así que estoy limitando mis resultados a cinco por mucho.

¡Eso es todo! Si tu buscas por un elemento en esta aplicación ahora, verás (basado en mi consulta) que si escribiste caracteres que coincidan con el nombre de un elemento nombre o símbolo obtendrás un máximo de cinco recomendaciones.

Forzar la búsqueda cuando las pulsaciones de teclado sean detectadas

Hay un último truco del que deberíamos hablar y es permitir al usuario abrir la caja de búsqueda simplemente escribiendo. Para agregar una simple declaración en nuestros métodos OnLaunched y OnSuspending en nuestro archivo App.xaml.cs, podremos habilitar esta funcionalidad a través de nuestra aplicación entera.

Agrega esta línea a tu método OnLaunched.

SearchPane.GetForCurrentView().ShowOnKeyboardInput = true;

Y esta línea a tu método OnSuspending para deshabilitar lo cuando la aplicación esté cerrada.

SearchPane.GetForCurrentView().ShowOnKeyboardInput = false;

¡Y eso es todo! Corre tu aplicación y solo comienza a escribir. El botón de búsqueda se abrirá automáticamente y comenzará a capturar tus teclas presionadas.

Declaraciones

Hay una última cosa que quiero cubrir en este artículo y es mas para tu conocimiento que para algo que necesites hacer. Cuando tu agregaste el contrato de búsqueda a tu proyecto se agregaron muchos archivos a tu proyecto pero también hubo una declaración hecha en tu archivo appxmanifest. Si tu abres ese archivo y navegas a la tabla de Declaraciones verás algo como lo siguiente.

image

Sin esta declaración ninguna de las funcionalidades que has agregado a tu aplicación será capaz de funcionar. Obtendrás un erro diciendo que el acceso esta negado.

6-XAML-DeclarationError

Solo recuerda que necesitas declarar que estás usando la búsqueda antes de que tu aplicación este habilitada para hacer uso de esta API.

En resumen

Hoy, tomamos un vistazo rápido al agregar Búsquedas en tu aplicación. El contrato de búsqueda le da una nueva manera a tus aplicaciones de mostrarse a sus usuarios. Ahora solo necesitas determinar que es exatamente lo que quieres mostrar. Colócate frente a tus usuarios asegurará que estén inclinados por tu aplicación. Entre más lo uses más vida le darás.

Puedes descargar la solución entera de ejemplo desde aquí.

 

Mañana, vamos al paso final de la exploración de contratos, Compartir. ¡Nos vemos entonces!

Categories: Tutoriales, Windows 8 Tags:

31 días de Windows 8 | Día 5: El contrato de configuraciones

January 28th, 2013 No comments

Este artículo es una traducción de “Día 5: El contrato de configuraciones” de Jeff Blakenburg. Puedes encontrar aquí la versión original en inglés.

Hoy vamos a lanzar una serie de artículos enfocados en contratos iniciando con el contrato de configuraciones. Las oportunidades de que tu aplicación los use son realmente altas y quizá odies lidiar con ello. La configuración de la aplicación es solo una parte de algo más grande en Windows 8 llamado contratos. Vamos a iniciar nuestra conversación de configuraciones con la definición de Microsoft de contratos.

Contratos: Un contrato es como un acuerdo entre una o más aplicaciones. Los contratos definen los requerimientos que la aplicación debe cumplir para participar en estas interacciones únicas en Windows. Por ejemplo, Windows le permite a los usuarios compartir contenido de una aplicación a otra. La aplicación que comparte contenido hacia afuera soporta un contrato fuente al cumplir con requerimientos específicos mientras que la aplicación que recibe el contenido compartido soporta un contrato al cumplir un conjunto diferente de requerimientos. Ninguna aplicación necesita saber nada acerca de la otra. Cada aplicación que participa en el contrato de compartir puede ser independiente sin contar el flujo de información al compartir datos por Windows.

contrato

Interesante, esto suena como a una “interfaz administrada” entre aplicaciones en el sistema operativo Windows. Hay cinco contratos disponibles para nuestras aplicaciones:

  • Selector de archivos
  • Reproducir
  • Búsqueda
  • Configuración
  • Compartir

Tal como una interfaz típica de programación lo que significa que puede estar compartiendo algún tipo de funcionalidad sin que la otra sepa acerca de ello.

Con Windows 8, todo esto parece suceder en el nivel de experiencia de usuario. ¿Qué quiere decir? Bueno, vamos a tomar el contrato de compartir por ejemplo. Simplemente colócalo, las aplicaciones le dicen al sistema operativo para lo que ellas quieren ingresar. En el caso de compartir quizá sea aceptar o compartir una imagen, Windows se encargará del resto.

Imagina un escenario donde encuentres un gran artículo mientras navegas en la web en algo como Internet Explorer. Quieres compartirlo a alguien más vía correo o Twitter. Asumiendo que tenías una aplicación instalada que los gestione y ellas acepten el compartir una URI entonces Internet Explorer podría compartírselo. Mejor aún, esas aplicaciones ni siquiera tendrían que estar ejecutándose para hacerlo. Windows se encarga de hacer toda la magia.

Suena como una interfaz típica de programación ¿No es así?

Empezando simples

Si das un vistazo a muchos de los ejemplos afuera, vas a encontrar un conjunto complejo de métodos en diferentes páginas, si eres como yo terminarás confundido. Esta serie de artículos esta hecha para hacer los temas como este simples de entender y usar de modo que eso es lo que haré.

Cuando nuestra aplicación inicia hay un método en el archivo App.xaml.cs llamado OnLaunched que es ejecutado. Al principio de OnLaunched vamos a crear un manejador de eventos para cuando el usuario intente abrir el panel de configuración. Tus elementos no serán agregados hasta que el usuario trate de abrir la barra lateral (Charms bar) Este evento podrías ser usado cuando necesites pauser tu aplicación o juego y las configuraciones sean abiertas.

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
SettingsPane.GetForCurrentView().CommandsRequested += App_CommandsRequested;
Frame rootFrame = Window.Current.Content as Frame;
...
}

Una vez que has agregado el manejador de eventos, podemos ir abajo para agregar SettingsComands a nuestro SettingsPane. Hay muchos pasos para crear un SettingsCommand:

  • Crear un nuevo SettingsCommand: Esto requiere tres propiedades; un ID, una etiqueta y una acción para realizar cuando el comando sea presionado. En nuestro caso esto será creando un control Popup, llenarlo con un control de usuario que vamos a crear y desplazarlo desde un lado de la pantalla.
  • Manejar todos los casos de la destitución del control Popup: Nosotros también necesitaremos manejar el como regresar a nuestra aplicación cuando el usuario haya terminado la operación.

Si no lo has generado, necesitas un método para el manejador de eventos llamado App_CommandRequested o como elijas que puedes llamarlo. Aquí es donde haremos el volumen de nuestra lógica para que SettingsPane se comporte de la manera que queremos. Aquí está como luce el mío.

 

void App_CommandsRequested(SettingsPane sender, SettingsPaneCommandsRequestedEventArgs args)
{
SettingsCommand comando = new SettingsCommand("about", "Acerca de esta aplicación", (handler) =>
{
Popup popup = CrearItemConfiguracion(new AcercaDe(), 646);
popup.IsOpen = true;
});

args.Request.ApplicationCommands.Add(comando);
}

 

Como puedes ver arriba, creamos un nuevo objeto de tipo SettingsCommand y lo completamos con tres valores. A menos de que planees cambiar tu SettingsPane en tiempo de ejecución, el primero no importará mucho. Es un simple ID que puedes usar para hacer referencia al SettingsCommand después.La etiqueta “Acerca de esta aplicación” puede ser cualquier valor de tipo cadena pero recomendaría mantenerla por debajo de los 40 caracteres porque usar más podría truncarla. Finalmente, tenemos nuestro manejador para este comando. Este es el código que será ejecutado cuando el usuario seleccione la etiqueta. He simplificado este proceso usando una expresión lambda para definir el código y puedes ver que estoy creando un control de tipo Popup y ajustando su propiedad isOpen a true. Cambiar esta propiedad es lo que hace que el control Popup aparezca en la pantalla.

Creando el control Popup

En esta sección vamos a dar un vistazo al método BuildSettingsItem que he creado. Quizá hayas notadoque en el código de ejemplo de arriba que se están pasando dos valores. El primero es un control de usuario personalizado que estaremos creando en poco. Por ahora solo checa que AboutPage.xaml es un control de usuario que deberemos crear y que es usado para llenar al control Popup.

private Popup CrearItemConfiguracion(UserControl control, int ancho)
{
Popup mensaje = new Popup();
mensaje.IsLightDismissEnabled = true;
mensaje.ChildTransitions = new TransitionCollection();
mensaje.ChildTransitions.Add(new PaneThemeTransition()
{
Edge = (SettingsPane.Edge == SettingsEdgeLocation.Right) ? EdgeTransitionLocation.Right : EdgeTransitionLocation.Left
});

control.Width = ancho;
control.Height = Window.Current.Bounds.Height;
mensaje.Child = control;

mensaje.SetValue(Canvas.LeftProperty, SettingsPane.Edge == SettingsEdgeLocation.Right ? (Window.Current.Bounds.Width - ancho) : 0);
mensaje.SetValue(Canvas.TopProperty, 0);

return mensaje;
}

Mucho del código de este método es de “relleno” lo cual es para hacer de la IU un poco más amena y fluida. Las líneas específicas que son importantes son las últimas seis. Definimos el ancho y el alto de nuestro control de usuario, control y después lo asignamos como un hijo de nuestro control Popup mensaje (El ancho es recomendado de 346 o 646, el alto debería ser del tamaño de la pantalla del usuario de acuerdo a la guía de Microsoft). Finalmente ajustamos las propiedades left y top del popup de modo que aparezca en la ubicación adecuada y pasamos el popup de vuelta a nuestro SettingsCommand.

NOTA: Windows 8 puede de hecho transformar un bit basado en los ajustes de localización que han sido aplicados a la máquina. En países donde el lenguaje es leído de derecha a izquierda la barra de accesos está ubicada a la izquierda en lugar de la derecha. Esta es la razón por la que cuando asigne la propiedad LeftProperty de nuestra popup tenemos que verificar para ver en cual límite se encuentra el SettingPane. Deberías ver una lógica similar para el límite de PaneThemeTransition poco antes en este método.

Ciertamente no debes romper todo el código en pedazos como yo lo hice pero creo que eso hace las cosas más simples, especialmente cuando quieres crear múltiples elementos de tipo SettingsCommand.

Creando el control de usuario

Lo prometí antes, volveríamos aquí y aquí estamos. En este punto hemos tomado consideración de todo el andamio que es requerido para hacer funcionar al contrato de ajustes. Ahora todo lo que tenemos que hacer es construir una página para que se muestre. Agrega un nuevo control de usuario (UserControl) a tu proyecto. Yo lo he llamado AcercaDe.xaml para coincidir con el código que escribimos antes pero obviamente tu podrás usar el nombre que gustes.

image

El código de este archivo esta enteramente en tus manos. Aunque hay algunas recomendaciones en como debería lucir tu panel de ajustes, no hay reglas específicas al respecto. Lo que yo te estoy dando en el siguiente código de ejemplo y una plantilla de orden. Hará a tus aplicaciones lucir como esto.

De cualquier forma puedes usar cualquier XAML que te guste para hacer brillar a tu Popup.

<border BorderBrush="#00b2f0" BorderThickness="1,0,0,0">
<grid Background="White" VerticalAlignment="Stretch">
</grid><grid .RowDefinitions>
<rowdefinition Height="Auto"></rowdefinition>
<rowdefinition Height="*"></rowdefinition>
</grid>

<!-- HEADER -->
<grid Background="#00b2f0" Grid.Row="0">
</grid><grid .ColumnDefinitions>
<columndefinition Width="*"></columndefinition>
</grid>

<stackpanel Orientation="Horizontal" Grid.Column="0" Margin="40, 32, 17, 13">
<button x:Name="btnAtras" Margin="0,3,0,0" Style="{StaticResource BackButtonStyle}" Click="btnAtras_Click"></button>
<textblock Margin="10,10,0,0" FontFamily="Segoe UI" FontWeight="SemiLight" FontSize="24.6667" Text="Acerca de esta app" Foreground="White"></textblock>
</stackpanel>
<image Source="Assets/SmallLogo.png" Width="29" Height="29" Margin="353,46,17,21"></image>


<!-- CONTENT AREA -->
<scrollviewer VerticalScrollBarVisibility="Auto" Grid.Row="1">
<grid Margin="40,33,40,39" VerticalAlignment="Top" Grid.RowSpan="3">
<stackpanel>

</stackpanel>
</grid>
</scrollviewer>

</border>

No hay nada sustancialmente complicado acerca de este diseño. Tenemos tres controles que son importantes para el encabezado.

  • Button – El control del botón es la flecha con círculo. Hemos colocado un manejador del evento click llamado btnAtras_Click y te mostraré el código que contiene al final de este artículo.
  • Textblock – Contiene el nombre de los ajustes que el usuario estará viendo. En la mayoría de los casos, esto debería coincidir con las palabras que muestras en el SettingsPane.
  • Image – Esta imagen ciertamente no es requerida pero contribuye a reforzar tu marca y logo de una manera adicional. Puedo recomendarte el mostrar tu logo tanto como puedas y este es un gran lugar para hacerlo.

Hasta el fondo, tenemos una sección marcada como área de contenido. Dentro del contenedor StackPanel es donde deberías agregar tu contenido. Este puede ser lo que sea. pero trata de mantenerlo simple. CheckBox. ToggleButton, TextBox, RedioButton, etc. Los controles simples con la vista puesta en una tarea simple.

Aquí está el código para el método

private void BackButton_Click(object sender, RoutedEventArgs e)
{
Popup parent = this.Parent as Popup;
if (parent != null)
{
parent.IsOpen = false;
}

// If the app is not snapped, then the back button shows the Settings pane again.
if (Windows.UI.ViewManagement.ApplicationView.Value != Windows.UI.ViewManagement.ApplicationViewState.Snapped)
{
SettingsPane.Show();
}
}

Puedes ver que cerramos nuestro control popup padre y si la aplicacion no está en un estado snapped reabrirá el SettingsPane como lo haría un botón de retroceso. ¡Eso es todo!

Oh. Espera. ¡Querías saber como salvar la información del usuario?

Guardando información

Windows 8 ha cambiado muchas cosas y una de las conductas base que se han ido es el concepto del botón Guardar. Tanto como sea posible quiero que elimines ese concepto de tu cabeza.

Cuando un usuario cambia un valor en sus preferencias.

NO esperes para que ellos presionen un botón de Guardar cambios.

NO les preguntes ¿Está seguro? cuando el cambio es reversible.

Guarda la información en el momento en que ellos la cambien y dale a tu usuario crédito suficiente para hacer solo los cambios que el quiera hacer. Si ellos presionan la opción Borrar toda tu información esa podría ser la razón para confirmar que ellos están seguros pero solo hazlo porque no es reversible. No porque pienses que tu usuario es un idiota.

Y para el COMO, vamos a esperar en este tema para el día 8 y entonces consumiremos nuestro tiempo en guardar la información de ambas formas, tanto local como los valores en todas las máquinas en las que el usuario tenga una cuenta.

Resumen

Cuando toqué por primera vez Windows 8 yo seguía escuchando la frase “Win as 1” (Gana como uno). Gana como 1 es uno de los principales principios de Windows. Al principio esto sonaba como un discurso de marketing pero de hecho esta muy lejos de serlo. Habiendo trabajado con Windows 8 por un tiempo, los contratos son una prueba genial de este principio. Cosas como los ajustes de la aplicación ahora están centralizados en el usuario, nuestras aplicaciones ahora pueden pasar mas tiempo enfocadas en mostrar sus elementos clave en lugar de lidiar con cosas como las configuraciones. Además, ahora que las configuraciones son consistentes en todas las aplicaciones, nunca más tendremos que enseñar a un usuario a usar las configuraciones más que una sola vez.

Yo solo tuve que pensar en como abrir una puerta y después, las pude abrir todas

-Yo lo invente

Hoy, vimos el contrato de configuraciones el cual es solo uno de muchos contratos que encontrarás en Windows 8. Así como una interfaz de programación, los contratos en Windows 8 le ofrecen a tu aplicación una manera única de extender tu aplicación más allá de la definición tradicional de un proceso de aplicación dando mejor una consistencia en el uso de interfaces a nuestros usuarios.

Puedes descargar la solución entera de ejemplo aquí.

Mañana vamos a mirar al contrato de Búsqueda. Buscar el algo que encontrarás muy útil no solo desde una perspectiva de usabilidad sino también porque es una manera rápida de continuar manteniendo tu aplicación en la cima de tus usuarios. ¡Nos vemos!

Categories: Tutoriales, Windows 8 Tags: