Archive

Posts Tagged ‘Silverlight’

WCF Ria Services V1.0 para Silverlight 4.- Agregar un nuevo registro hacia la Base de Datos (Parte 8)

May 18th, 2012 1 comment

En nuesto post pasado, pudimos ver cómo editar los datos que se presentan en nuestra aplicación silverlight (lado del cliente), pero aún más importante cómo es que se hace la actualización de estos cambio en la base de datos. Si no has leido este post, te recomiendo lo leas, ya que utilizaremos la información mostrada en este siguiente post.

Nuestro siguiente tema abordará el conceto de agregar un nuevo registro, pero además se mostraran un par de puntos a considerar cuando se está agregando un registro.

Agregando un nuevo registro al cliente

Para agregar un nuevo registro solo basta escribir un par de lineas de código, en donde básicamente lo que se hace es crear un nuevo objecto del tipo de datos que vamos a insertar y este se agrega al DomainDataSource que contiene los datos.

Para insertar el código del que hablabamos, en nuestra vista incluiremos un botón que nos permita indicar a la aplicación que queremos agregar un nuevo registro.

<Button x:Name="btnAddNew"
        Content="Agregar nuevo"
        Height="23"
        Width="115"
        HorizontalAlignment="Left"
        Click="btnAddNew_Click" />

Y será en el evento del click donde escribiremos las lineas de creación del objecto del nuevo producto, añadiendolo a los elementos del DataView de nuestro Domain Data Source.

private void btnAddNew_Click(object sender, System.Windows.RoutedEventArgs e)
{
    WcfRiaServices.Web.Models.Product newProduct = new Web.Models.Product();
    productDomainDataSource.DataView.Add(newProduct);
}

Con esto lo que estamos haciendo es agregar un nuevo elemento al Domain Data Source, quién es el encargado de contener los datos de lado del cliente. Y, al igual que cuando queremos editar un elemento, necesitamos replicar este cambio a nuestro servicio que será el que haga la actualización en la base de datos. Como a estas alturas ya tenemos nuestro botón de ‘Guardar Cambios’ esta parte ya la tenemos cubierta.

Algunas consideraciones extras

Debido a que la tabla de Productos tiene algunos campos que no pueden ser nulos, además de que a estas alturas no tenemos ningun tipo de validación ni en nuestro modelo ni al momento de guardar los cambios. Sugiero al momento de crear el nuevo objeto, inicializar las propiedades que así lo requieran

private void btnAddNew_Click(object sender, System.Windows.RoutedEventArgs e)
{
    WcfRiaServices.Web.Models.Product newProduct = new Web.Models.Product();
    newProduct.rowguid = System.Guid.NewGuid();
    newProduct.SafetyStockLevel = 1000;
    newProduct.ReorderPoint = 500;
    newProduct.DiscontinuedDate = System.DateTime.Now;
    newProduct.ModifiedDate = System.DateTime.Now;
    newProduct.SellEndDate = System.DateTime.Now;
    newProduct.SellStartDate = System.DateTime.Now;
    productDomainDataSource.DataView.Add(newProduct);
}

Siguientes post…

Ya solo nos falta revizar como eliminar un registro para poder terminar con el tema de CRUD, permitiendonos así continuar con temas como validaciones o el indicator de acción (Busy Indicator)

Gracias y saludos

Silverlight RIA Services y Windows Azure TableStorage

March 29th, 2012 No comments

 

Un escenario común al trabajar en Silverlight y SQL Server  es utilizar RIA Services para realizar operaciones CRUD, RIA services ofrece muchas ventajas, pero una vez más al pensar en la nube  debemos replantear cual es la mejor solución para minimizar costos de nuestra implementación .

Una alternativa es usar TableStorage de Windows Azure para realizar estas operaciones.

Para lograr esto necesitamos tener instalados los siguientes componentes:

Windows Azure SDK

La última version de RIA Services.

Teniendo todo listo podemos comenzar.

1.- Creamos un nuevo proyecto de silverlight con RIA Services habilitado.

2.- Agregamos un nuevo proyecto Cloud de Windows Azure en limpio.

3.-En nuestro proyecto Cloud de Windows Azure agregamos nuestro WebRole que ya existe en nuestra solución.

image

4.- En nuestro proyecto Web  agregamos un Domain Services en Blanco .

 

5.-Necesitamos agregar a nuestro proyecto Web las siguientes referencias:

  • System.Data.Services.Client
  • Microsoft.WindowsAzure.ServiceRuntime
  • Microsoft.WindowsAzure.StorageClient
  • Microsoft.ServiceModel.DomainServices.WindowsAzure

Con esto hemos preparado nuestro entorno para poder trabajar con TableStorage y RIA Services.

TableEntity

Como ya sabemos TableStorage ofrece muchas ventajas una de ellas es que ofrece un número practicamente ilimitado de tablas y registros , además que ofrece una forma estructurada de almacenamiento de nuestra información.

Algo que debemos recordar es que cada registro deben tener obligatoriamente 3 propiedades PartitionKey,RowKey,Timestamp, la combinacion de estas 3 propiedades forman una unica llave que identifica nuestro registro.

Para simplificar este trabajo nosotros podemos hacer uso de la clase TableEntity , esta clase incluye ya estas propiedades.

Ejemplo:

Lo que sigue es crear el DataContext para el Table Storage esto lo logramos gracias a la clase TableEntityContext

Por ultimo necesitamos agregar diversos metodos a nuestro Domain Service.

Con esto nostros podemos fácilmente realizar operaciones CRUD con RIA Services y Table Storage.


Puedes descargar el código fuente Aquí

La Entrevista MVP presenta a… Michael Crump

October 31st, 2011 No comments

En esta ocasión entrevistamos a Michael Crump, MVP de Silverlight. MVP_Horizontal_BlueOnly


(LLS)  Hola Michael, cuéntanos acerca de ti.

(MC) Soy un MVP en Silverlight y MCPD que actualmente trabaja para Telerik como Evangelista de XAML. Soy muy apasionado de XAML y he trabajado en varios proyectos importantes de Silverlight / WPF.

(LLS)  Cuéntanos sobre tu último proyecto de desarrollo en el que estuviste involucrado.

(MC) Estuve involucrado en la creación de un reproductor de vídeo en Silverlight 4 para un hospital local. Distribuía contenidos en video a los pacientes al darlos de alta, y también lo hacía para entretenerlos durante su estancia.

(LLS)   ¿Cuál es tú opinión sobre Windows 8 mostrado en la conferencia Build?

(MC)  Creo que es una buena noticia. Estoy muy emocionado de escuchar acerca de las posibilidades de WinRT y ya he comenzado a desarrollar aplicaciones WinRT con XAML y C#.

(LLS)  ¿Cuáles son sus tres características favoritas de Silverlight y por qué?

(MC)  a. Depuración en XAML – Me encanta la posibilidad de establecer puntos de interrupción en XAML. Esto ayuda a encontrar errores en tus declaraciones de Enlace de Datos en un instante!

b. P/Invoke – La capacidad de detectar las unidades USB en una aplicación de Navegador Web no tiene precedentes.

c. Aplicaciones Fuera del Navegador – No es nuevo para Silverlight 5, pero sigue siendo una gran característica para hacer que tu aplicación aparezca instalada en la máquina local.

(LLS)  ¿Cuál es tú consejo para las empresas que están tratando de elegir entre Silverlight y HTML?

(MC)  Realmente tienes que escoger cuál es la mejor tecnología para tu proyecto actual. Si estás construyendo Aplicaciones de Negocio internas, entonces yo me iría por Silverlight. Si se trata de un sitio Web público, entonces probablemente me iría por HTML 5.

(LLS)  ¿Qué llevas en tu bolsa de laptop?

(MC)  Además del equipo normal, llevo cables de extensión, cables de red, batería adicional para la laptop, papel y lápiz así como medicinas para el dolor de cabeza. =)

(LLS)  ¿Un último consejo para todos tus lectores de habla hispana?

(MC)  No se dejen atrapar por toda la emoción alrededor de las nuevas tecnologías. Miren las necesidades de sus clientes y continúen desde allí. Yo soy promotor de la adopción temprana de tecnologías, pero siempre doy un paso atrás en lo que respecta a las necesidades de mi cliente.


Michael Crump es un MVP en Silverlight y MCPD que trabaja para Telerik como un Evangelista de XAML. Ha estado involucrado con computadoras de una u otra forma desde que tiene memoria, pero se inició profesionalmente en el año 2002. Después de pasar años trabajando como administrador de sistemas / analista de soporte técnico, Michael se ramificó y empezó a desarrollar utilerías internas para automatizar tareas repetitivas y de esa forma liberar el tiempo de los empleados. A partir de ahí, se le ofreció un trabajo en McKesson Corporation y ha estado trabajando con. NET y Visual Basic/C# desde 2003.   Puedes seguir a Michael en Twitter y mantenerte al día con su blog mediante la suscripción de su RSS Feed..

Categories: Entrevista MVP Tags: , ,

La Entrevista MVP presenta a… Braulio Diez

October 22nd, 2011 No comments

En esta primera entrevista, platicamos con Braulio Diez, Silverlight MVP de Málaga, España.


(LLS) Hola Braulio, gracias por tu tiempo

(BD) Gracias a vosotros, un honor que hayáis contactado conmigo.

(LLS) Por favor cuéntanos acerca de ti

(BD) Soy un profesional Freelance, especializado en el área de desarrollo web, y este es mi tercer año como MVP en Silverlight.

(LLS) Por favor cuéntanos acerca del último proyecto en el que estuviste involucrado

(BD) Como buen Freelance me toca estar involucrado en varias iniciativas en paralelo, … digamos que así no tengo tiempo de “aburrirme”, lo que más me ha gustado:

  • SilverDiagram un motor de diagramas que nos permite implementar de forma fácil diversos tipos de aplicaciones: en breve publicaremos el código fuente de este editor de diagramas de redes (http://silverdiagram.net/Scripts/SD.Editor.html), y también estamos preparando la puesta en producción de un editor que permite definir accidentes de trafico.

clip_image002

clip_image004

(LLS) ¿Qué aconsejarías a una empresa que está tomando la decisión entre Windows Forms, WPF y Silverlight?

(BD) Yo les haría una serie de preguntas:

  • ¿Qué tecnologías de desarrollo conoce su equipo?
    • Si su equipo sólo conoce WinForms, el salto a WPF y Silverlight requiere formación, esto hace que podamos aprovechar toda la potencia de esta tecnología (si no acabamos utilizándolo como si fuera WinForms, lo que llamamos algunos desarrolladores… Silverlight en Modo VB 6.0).
  • ¿Qué tipo de aplicación quieren realizar?
    • Si es una aplicación de gestión (como dicen los ingleses LOB), Silverlight y WPF incorporan un montón de mejoras que hacen que sea la plataforma ideal.
    • Si es una aplicación compleja (por ejemplo algo tipo Visual Studio o tipo Photoshop), habría que pensar utilizar WPF y aprovechar toda la potencia nativa.
  • ¿Quieren que su aplicación sea robusta y fácilmente mantenible?
    • En este aspecto merece la pena invertir en Silverlight o WPF e implementar el patrón MVVM + IOC, una combinación muy buena de librerías para esto: MVVM Light Toolkit + MEF.
  • ¿Quieren ahorrarse problemas de instalación y versionado?
    • Cuando hacemos un desarrollo desktop con WinForms y WPF todos hemos sufrido algún problema con nuestros clientes: no siempre todos los desktop tienen la última versión de nuestro software, en algunas máquinas hay conflictos a la hora de instalar… con Silverlight no necesitamos realizar este tipo de instalaciones, el usuario siempre trabajo con la última versión de la aplicación y no hay problemas con DLL’s o versión de .net framework que estén instalados en la máquina cliente.
  • ¿Quieren disfrutar de una experiencia Mixta Web y Desktop?
    • Silverlight permite ejecutar nuestra aplicación integrada en nuestro navegador web, o también instalarla como si fuera una aplicación desktop (OOB), que además nos ofrece:
      • Chequear actualizaciones y tener siempre la última versión de la aplicación descargada.
      • Poder tener aplicaciones desktop trusted que permiten acceder a operaciones especiales (ej acceder al sistema de ficheros del ordenador, o realizar llamadas COM o a DLL’s no manejadas vía p/invoke).
  • ¿ Quieren tener control de seguridad?
    • Las aplicaciones Silverlight corren dentro de un SandBox, esto es un entorno limitado que evita que una aplicación maliciosa (o por accidente) pudiera borrar ficheros o acceder a información confidencial de su disco duro sin su permiso.
    • Si necesita salir del SandBox tenemos la opción de implementar aplicaciones “trusted”, estás aplicaciones sólo se ejecutan con el permiso expreso del usuario.

Windows 8 trae dos sabores el de Metro, y el clásico (tipo Win 7), para las aplicaciones desktop que utilicemos para el trabajo tiene pinta que el interfaz que va a predominar es el desktop.

(LLS) ¿Qué impacto crees que tengan las aplicaciones Metro con respecto a las aplicaciones de escritorio actuales?

(BD) Buena pregunta, aquí debemos siempre leer entre líneas: Microsoft tiene previsto sacar un nuevo Sistema Operativo en el que la principal novedad es un interfaz táctil muy visual, debemos tener en cuenta:

- El principal target de Metro son las tablets, habrá que ver si este interfaz tiene éxito en ordenadores de sobremesa o laptops ¿ Conseguirán que nos compremos pantallas táctiles?.

- Las aplicaciones metro en un principio sólo se podrán vender via Market Place (algo parecido a lo que pasa con WP7). Se espera que con el tiempo se puedan incorporar otro tipo de desarrollo que no sea el orientado a “consumer market”.

- Windows 8 trae dos sabores el de Metro, y el clásico (tipo Win 7), para las aplicaciones desktop que utilicemos para el trabajo tiene pinta que el interfaz que va a predominar es el desktop.

- Metro está en un estado muy prematuro, hace unas semanas se hablaba de que el browser de metro no iba a soportar ningún tipo de plugin (http://blogs.msdn.com/b/b8/archive/2011/09/14/metro-style-browsing-and-plug-in-free-html5.aspx), para después mostrar una demo en la que se puede ver el plugin de flash corriendo en una Tablet (http://channel9.msdn.com/posts/Windows-8-Running-on-ARM).

- Tambíen en Metro podemos desarrollar aplicaciones nativas con XAML y .net con soporte a WinRT, esto hace que nuestro conocimientos en Silverlight / WPF podamos reaprovecharlos también para implementar aplicaciones Metro.

(LLS) ¿Qué aconsejarías a un desarrollador que está comenzando en el mundo de desarrollo de Silverlight?

(BD) Que se baje la versión 5 del producto, se compre un buen libro, chequee los videos y tutoriales de La Liga de Silverlight y empezará a divertirse con esta tecnología, muy importante: primero centrarse en aprender lo básico, después emplear tiempo en aprender a implementar el patrón MVVM.

Otro consejo es que especialice su carrera en dos tecnologías, por ejemplo Silverlight y ASP .net MVC / HTML 5 ¿ Por qué? Siempre es bueno ver que ofrece cada una, tener argumentos, y ver donde aplicar la mejor para cada caso, por ejemplo para realizar una aplicación de gestión o web, con Silverlight podemos hacer algo en poco tiempo y con muy buen nivel de calidad y usabilidad, sin embargo si queremos implementar un portal web o una aplicación web que corra entre otros dispotivos en iPhone, HTML5 es la opción a elegir.

Es impresionante constatar la evolución que tiene el área de desarrollo en América Latina, tenéis grupos y comunidades muy fuertes

(LLS) ¿Cuál es el impacto que tú percibes con respecto al desarrollo de software en América Latina?

(BD) Es impresionante constatar la evolución que tiene el área de desarrollo en América Latina, tenéis grupos y comunidades muy fuertes (cómo La Liga de Silverlight), empresas de profesionales muy especializados como Nektra, y también capacidad para albergar grandes factorías de Software.

A largo plazo creo que el mejor camino a seguir es la especialización. En mi caso he tenido la suerte de trabajar con excelentes profesionales de allá, y tengo buenos clientes de nuestro motor de diagramas.

(LLS) ¿Algún último consejo para nuestros lectores hispanoparlantes?

(BD) Sí, que piensen bien a que se quieren dedicar, que elijan una tecnología en la que se diviertan y se sientan a gusto… en nuestro trabajo se tienen que dedicar demasiadas horas como para encima estar haciendo algo en lo que uno no se siente realizado.

Accediendo a tus ensamblados de .NET desde Silverlight–Parte 2

July 27th, 2011 No comments

En el artículo anterior, vimos el uso de la clase AutomationFactory para poder crear objetos de tus ensamblados creados con el .NET Framework 4.0, y utilizarlos en Silverlight.

En el ejemplo, invocamos un método como cualquier otro y efectivamente obtenemos los resultados esperados, en este caso, la lista de unidades lógicas del equipo del usuario en donde está ejecutando la aplicación.  Pero ¿qué pasaría si necesitáramos manejar un evento que es disparado por el componente (tu ensamblado) de .NET?  En este caso la implementación debe cumplir con ciertos requisitos.

Atributo ComSourceInterfacesAttribute

Para que podamos exponer un evento en nuestro ensamblado, y que pueda ser manejado por la aplicación de Silverlight a través de automatización, debemos marcar nuestra clase que implementa el evento con el atributo ComSourceInterfacesAttribute, el cual indica una lista de interfaces que contienen los eventos a exponer en dicha clase.

Puedes leer el artículo completo aquí

Accediendo a tus ensamblados de .NET desde Silverlight

July 27th, 2011 No comments

El BCL (Biblioteca de Clases Base, por sus siglas en inglés) de Silverlight está reducido a comparación del BCL del .NET Framework completo que tenemos instalado en nuestros equipos, por lo que la funcionalidad no es la misma en un aplicativo de Silverlight que alguno construido con el .NET Framework completo.

No obstante, a partir de Silverlight 4, es posible que las aplicaciones de Silverlight sean clientes de automatización cuando ejecutan en Confianza Elevada, esto es, poder invocar los servidores de automatización registrados en el sistema operativo Windows.  Generalmente, la mayoría de ejemplos que podemos encontrar en la Web al respecto de esta característica van por el lado de invocar los servidores de automatización de Office (Outlook.Application o Excel.Application por ejemplo), pero ¿qué sucede si necesitamos invocar funcionalidad ya construida en alguno de nustros ensamblados que hayamos escrito en .NET 4.0?

Ensamblado

En esta solución crearemos dos proyectos, uno de tipo Class Library del .NET Framework 4.0 y otro proyecto será la aplicación de Silverlight.

En el proyecto de la Biblioteca de Clases escribiremos la funcionalidad para obtener la información de todas las unidades lógicas del equipo.  Tradicionalmente, esto lo podemos lograr por medio de la clase DriveInfo del espacio de nombres System.IO, pero justamente esa es una de las clases que no está en el BCL de Silverlight, por lo que crearemos un ensamblado de .NET 4.0 que regrese esa información, y la usaremos en un aplicativo de Silverlight.

La clave para lograr esto es abrir las propiedades del proyecto de la Biblioteca de Clases y seleccionar la opción “Register for COM interop” para poder exponer este ensamblado a través de COM.

Puedes leer el artículo completo aquí

Desarrollando con el GPS de Windows Phone (Servicios de Ubicación)

June 21st, 2011 No comments

Desarrollando con el GPS de Windows Phone (Servicios de Ubicación)

Este artículo es una traducción del artículo original encontrado en: http://create.msdn.com/en-US/education/quickstarts/Developing_with_the_Windows_Phone_GPS_%28Location_Services%29 .

 

Silverlight para Windows Phone incluye un espacio de nombres que proporciona un control y monitoreo en tiempo real de los servicios de la ubicación del teléfono. El servicio de ubicación proporciona la mejor información disponible sobre la ubicación actual del teléfono mediante una combinación de Wi-Fi y datos de red de celular, así como datos de un sistema de posicionamiento global (GPS). El servicio de ubicación traza la longitud actual, la latitud, la altitud, la velocidad del recorrido, y la dirección del teléfono, exponiendo el acceso a estos datos a través del espacio de nombres System.Devices.Location.  

 

La creación de una aplicación del teléfono que tenga noción de la ubicación implica que ciertas funcionalidades en tu aplicación estarán sujetas a la disponibilidad de datos de ubicación. Debido a que los Servicios de Ubicación se basan en señales de celular y de satélites, es importante escribir código que maneje los siguientes escenarios:

 

·         El usuario ha encendido los receptores GPS y/o de celular en el dispositivo.

·         La cobertura de la señal es muy pobre para recibir datos de ubicación.

·         El servicio de ubicación todavía esta inicializando o esperando por datos de ubicación para alcanzar al dispositivo.

Estaremos codificando esta aplicación de tal manera que permita al usuario manejar estos escenarios.

 

Este tutorial es una aplicación de Silverlight para Windows Phone, que recibe entrada del servicio de ubicación de Windows Phone 7 y traza los datos en un mapa mientras que indica una lectura visual de los datos.  Este artículo está dividido en las siguientes secciones:

·         Creando una interfaz de usuario para la lectura del servicio de ubicación.

·         Obteniendo datos en tiempo real del servicio de ubicación.

·         Consideraciones finales.

Descarga el código fuente completo para este tutorial, hospedado en la galería de código de Silverlight para Windows Phone.

 

Inicio rápido en video

Para ver un ejemplo de este tutorial ejecutando en un teléfono real, y para construir este tutorial siguiendo un video en vez de continuar leyendo este artículo, puedes ver el video a continuación. La página de este video en el Channel 9 tiene varias opciones de descarga, si quisieras una versión de alta definición, o si quisieras descargar una versión que pueda ser reproducida en otros dispositivos, además de una computadora.

 

Creando una interfaz de usuario para la lectura del servicio de ubicación.

Inicia Visual Studio y comienza un proyecto de tipo "Silverlight para Windows Phone". A continuación, crea una interfaz de usuario que tendrá los siguientes elementos:

 

·         Seis campos TextBlock con nombres significativos, para la lectura de la longitud, latitud, velocidad, curso, altitud, y el estado de los datos.

·         Un objeto Map, sobre el que vamos a colocar un Pushpin con la ubicación actual del teléfono.  Nota: Necesitas obtener una clave de Bing Maps con el fin de utilizar el control del mapa. Para obtener una, sigue las instrucciones en el artículo Obteniendo una clave de Bing Maps.  Una vez que tengas una clave, que es simplemente una cadena, introduce la cadena como el valor de la propiedad CredentialsProvider en el código XAML que define el objeto Map. Se proporciona un ejemplo en el artículo Accediendo al control usando una clave de Bing Maps.

·         Dos Buttons con nombres significativos que serán utilizados para iniciar y detener el servicio de ubicación e iniciar el trazado en tiempo real de la posición del teléfono en el Mapa.

·         TextBlocks según sea necesario para proporcionar el etiquetado de la información de lectura.

 

Una distribución sugerida de estos elementos se proporciona a continuación.  En este caso, los valores predeterminados para los seis TextBlocks que proporcionan los datos de lectura cambia para mostrar el formato y los parámetros utilizados por el servicio de ubicación cuando proporciona los datos (por ejemplo, "Metros Por Segundo" es el valor predeterminado de velocidad, por lo que está claro después).

 

clip_image002

XAML

 

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,12">

<TextBlock Height="30" Margin="12,6,395,0" Name="textBlock1" Text="Long:"

VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,42,0,0" Name="textBlock2"

Text="Lat:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="71,6,0,0"

Name="longitudeTextBlock" Text="Long" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="53,42,0,0"

Name="latitudeTextBlock" Text="Lat" VerticalAlignment="Top" />

<my:Map Height="352" HorizontalAlignment="Left" Margin="12,322,0,0" Name="myMap"

VerticalAlignment="Top" Width="421" CredentialsProvider="KEY" ZoomLevel="1" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,196,0,0"

Name="textBlock3" Text="Status:" VerticalAlignment="Top" />

<TextBlock Height="66" HorizontalAlignment="Left" Margin="78,196,0,0"

Name="statusTextBlock" Text="Status TextBlock w/TextWrapping=&quot;Wrap&quot;"

VerticalAlignment="Top" Width="355" TextWrapping="Wrap" />

<Button Content="Track Me On Map" Height="72" HorizontalAlignment="Left"

Margin="0,256,0,0" Name="trackMe" VerticalAlignment="Top" Width="255"

Click="trackMe_Click" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,78,0,0"

Name="textBlock4" Text="Speed:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="78,78,0,0"

Name="speedreadout" Text="Meters Per Second" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,114,0,0"

Name="textBlock6" Text="Course:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="84,114,0,0"

Name="coursereadout" Text="Heading in Degrees (0=N)" VerticalAlignment="Top"

Width="339" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,150,0,0"

Name="textBlock5" Text="Altitude:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="93,150,0,0"

Name="altitudereadout" Text="Altitude in Meters (0=Sea Level)"

VerticalAlignment="Top" />

<Button Content="Stop LocServ" Height="72" HorizontalAlignment="Left"

Margin="235,256,0,0" Name="startStop" VerticalAlignment="Top"

Width="209" Click="startStop_Click" />

</Grid>

 

 

Para que el XAML de arriba funcione, necesitas definir el espacio de nombres "my:Map" que se utiliza al agregar un atributo xmlns en la etiqueta phone:PhoneApplicationPage en la parte superior del documento XAML que define la interfaz de usuario, de la siguiente manera:

 

XAML

<phone:PhoneApplicationPage

xmlns:my=

"clr-  

namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls

    .Maps">

 

Por último, si Visual Studio no lo ha hecho automáticamente en respuesta a estos elementos de la interfaz de usuario definida, agrega una referencia a Microsoft.Phone.Controls.Maps. Silverlight para Windows Phone utiliza el ensamblado Microsoft.Phone.Controls.Maps para proporcionar funcionalidad de mapeo, por lo que debes hacer referencia en tu proyecto antes que cualquiera de sus tipos, eventos o métodos se pueden utilizar en tu aplicación.

 

Para agregar Microsoft.Phone.Controls.Maps a su aplicación:

1.       En el Explorador de Soluciones, haz clic en el nodo References en tu proyecto y, a continuación, selecciona Agregar Referencia.

2.       Selecciona Microsoft.Phone.Controls.Maps de la lista, a continuación, haz clic en OK.

 

Nota: Visual Studio automáticamente agregar el atributo xmlns en la parte superior de la página XAML y agrega la referencia a Microsoft.Phone.Controls.Maps si agregas el control Map a la interfaz de usuario arrastrándolo hasta el diseñador desde el cuadro de herramientas.

 

Obteniendo datos en tiempo real del servicio de ubicación

En el Explorador de Soluciones, abre el archivo MainPage.xaml.cs, y agrega las siguientes tres líneas de código en la parte superior de la página.

 

C#

using Microsoft.Phone.Controls.Maps;

using System.Device.Location;

using System.Threading;

 

Visual Basic

 

Imports Microsoft.Phone.Controls.Maps

Imports System.Device.Location

Imports System.Threading

 

Esto da a tu código C# acceso al control de Bing Maps, el API del servicio de ubicación, y el modelo de Hilos, que vamos a utilizar para este tutorial.

El uso del servicio de ubicación para Windows Phone requerirá coordinación a través de algunos métodos, por lo que vamos a añadir algunos datos a los miembros de la clase principal. Lo más notable será el objeto GeoCoordinateWatcher, que recibe constantemente el servicio de ubicación más reciente tan pronto se haya "iniciado" a través del método TryStart(), que vamos a demostrar en un momento.  Vamos a llamar watcher al nuestro.  Tan pronto como el watcher ha sido iniciado, intentará recuperar la información de ubicación del Servicio de Ubicación, expondrá esa información a través de sus diversas propiedades, y también disparará el evento PositionChanged cuando la información de ubicación sea actualizada (es decir, cuando el dispositivo cambie de ubicación).

Este miembro de datos debe ser a nivel de clase, porque son varios los métodos que deben participar en la lectura de entrada de servicios de ubicación con el fin de manejar los diversos eventos que disparará el servicio de ubicación.

Además, vamos a verificar si el usuario ha habilitado el rastreo en mapa, de modo que será también un miembro de datos de la clase.  Por último, vamos a utilizar el objeto Pushpin en todo el tutorial, ya que sólo necesitamos uno y constantemente actualizaremos su posición en los diferentes métodos se creará una instancia a nivel de clase.  Los tres miembros de datos resultantes se observan en el siguiente código:

C#

public partial class MainPage : PhoneApplicationPage

{

GeoCoordinateWatcher watcher;

bool trackingOn = false;

Pushpin myPushpin = new Pushpin();

..

 

Visual Basic

 

Public Partial Class MainPage

Inherits PhoneApplicationPage

Private watcher As GeoCoordinateWatcher

Private trackingOn As Boolean = False

Private myPushpin As New Pushpin()

 

Como se ha mencionado, habrá varios métodos involucrados con el manejo de watcher. De hecho, serán tres:

 

1.       Un método que maneja el evento PositionChanged de watcher y procesa los nuevos datos.  Vamos a llamar a este método watcher_PositionChanged.

2.       Un método que maneja el evento StatusChanged de watcher que se dispara cuando el servicio de ubicación cambia su estado de estar inactivo, a inicializando, a recibiendo datos, y todos los puntos intermedios.  Vamos a llamar a este método watcher_StatusChanged.

3.       Un método que se encargará de iniciar el  watcher por su cuenta, en su propio hilo. Aunque este método sólo será una línea de código, queremos dividir ese código para que se pueda ejecutar en su propio hilo y no hacer que la aplicación se bloquee cuando el servicio de ubicación inicialice.  Llamaremos a este método startLocServInBackground.

 

Es sólo una línea de código de cada uno para conseguir estos métodos implementados en el tutorial.  También podríamos hacerlo cuando se inicia la aplicación, así que vamos a añadir al constructor de esta aplicación, el método MainPage.

 

Un par de líneas adicionales son necesarias para instanciar watcher y actualizar la interfaz de usuario sobre el progreso de la inicialización del servicio de ubicación, dejando MainPage de la siguiente manera:

 

C#

// Constructor

public MainPage()

{

InitializeComponent();

// Crear una instancia watcher, estableciendo su nivel de precisión y el umbral de movimiento.

watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); // using high accuracy;

watcher.MovementThreshold = 10.0f; // meters of change before "PositionChanged"

// Conecta los manejadores de eventos

watcher.StatusChanged += new

EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged);

watcher.PositionChanged += new

EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);

/ / Iniciar LocServ en bg; watcher_StatusChanged ,se llamará cuando se complete.

new Thread(startLocServInBackground).Start();

statusTextBlock.Text = "Starting Location Service…";

}

Visual Basic

‘Constructor

Public Sub New()

InitializeComponent()

Crear una instancia watcher, estableciendo su nivel de precisión y el umbral de movimiento.

watcher = New GeoCoordinateWatcher(GeoPositionAccuracy.High)

‘usando alta precisión

watcher.MovementThreshold = 10F

Metros antes del cambio "PositionChanged"

‘Conecta los manejadores de eventos

watcher.StatusChanged += New EventHandler(Of GeoPositionStatusChangedEventArgs)(watcher_StatusChanged)

watcher.PositionChanged += New EventHandler(Of GeoPositionChangedEventArgs(Of GeoCoordinate))(watcher_PositionChanged)

Iniciar LocServ en bg; watcher_StatusChanged ,se llamará cuando se complete.

New Thread(startLocServInBackground).Start()

statusTextBlock.Text = "Starting Location Service…"

End Sub

 

Ahora, implementaremos los manejadores de eventos.  Vamos a empezar con watcher_StatusChanged.  watcher expresará su estado a watcher_StatusChanged mediante el uso de un objeto GeoPositionStatusChangedEventArgs, que es pasado como argumento. Este objeto tiene una propiedad de tipo enum llamada GeoPositionStatus que proporciona los nombres descriptivos de los diferentes estados del servicio de ubicación.  Todo lo que queremos hacer en nuestro tutorial es notificar al usuario que el estatus ha cambiado, y lo podemos lograr con una simple sentencia switch que maneja los cuatro posibles valores de GeoPositionStatus, de esta manera:

C#

void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e)

{

switch (e.Status)

{

case GeoPositionStatus.Disabled:

/ / El Servicio de Localización está deshabilitado o no soportado.

/ / Comprueba si el usuario ha desactivado el servicio de ubicación

 if (watcher.Permission == GeoPositionPermission.Denied)

{

/ / El usuario ha desactivado el servicio de ubicación en su dispositivo.

statusTextBlock.Text = "You have disabled Location Service.";

}

else

{

statusTextBlock.Text = "Location Service is not functioning on this device.";

}

break;

case GeoPositionStatus.Initializing:

statusTextBlock.Text = "Location Service is retrieving data…";

// El Servicio de ubicación se está iniciando.

break;

case GeoPositionStatus.NoData:

// El Servicio de Ubicación está trabajando, pero no puede obtener datos de Ubicación.

statusTextBlock.Text = "Location data is not available.";

break;

case GeoPositionStatus.Ready:

// El Servicio de Ubicación está trabajando y está recibiendo los datos de Ubicación.

statusTextBlock.Text = "Location data is available.";

break;

}

}

Visual Basic

Private Sub watcher_StatusChanged(sender As Object, e As GeoPositionStatusChangedEventArgs)

Select Case e.Status

Case GeoPositionStatus.Disabled

El Servicio de Localización está deshabilitado o no soportado.

Comprueba si el usuario ha desactivado el servicio de ubicación

If watcher.Permission = GeoPositionPermission.Denied Then

El usuario ha desactivado el servicio de ubicación en su dispositivo.

statusTextBlock.Text = "You have disabled Location Service."

Else  

statusTextBlock.Text = "Location Service is not functioning on this device."

End If

Exit Select

Case GeoPositionStatus.Initializing

statusTextBlock.Text = "Location Service is retrieving data…"

El Servicio de ubicación se está iniciando.

Exit Select

Case GeoPositionStatus.NoData

El Servicio de Ubicación está trabajando, pero no puede obtener datos de Ubicación.

statusTextBlock.Text = "Location data is not available."

Exit Select

Case GeoPositionStatus.Ready

El Servicio de Ubicación está trabajando y está recibiendo los datos de Ubicación.

statusTextBlock.Text = "Location data is available."

Exit Select

End Select

End Sub

 

Ahora que podemos ver lo que sucederá cuando el servicio de ubicación se inicie y el evento StatusChanged sea disparado, vamos a implementar el método que realmente hace esta inicialización, al cual llamaremos startLocServInBackground.  Este método consiste en una sola línea, que llama al método TryStart de watcher, especificando un periodo de tiempo de espera de 60 segundos para la inicialización.  Ya que TryStart es síncrono, podría congelar la aplicación de todo ese período si no se ejecuta en un hilo secundario, por lo tanto, se usan hilos en la llamada a startLocServInBackground en el método MainPage.  El hilo que se inició en MainPage naturalmente terminará después del período de tiempo de espera de TryStart  o cuando watcher haya sido inicializado correctamente, lo que ocurra primero, y watcher_StatusChanged ya se haya implementado para manejar lo que sucede después de la inicialización, por lo que startLocServInBackground es muy simple:

 

C#

void startLocServInBackground()

{

    watcher.TryStart(true, TimeSpan.FromMilliseconds(60000));

}

 

Visual Basic

Private Sub startLocServInBackground()

       watcher.TryStart(True, TimeSpan.FromMilliseconds(60000))

End Sub

 

Antes de implementar watcher_PositionChanged, vamos a conectar dos botones que afectan el comportamiento de la aplicación cuando el dispositivo cambio de ubicación y, de hecho, si la ubicación esté siendo reportada que ha cambiado.  Hemos etiquetado los botones de la interfaz de usuario como "Track Me On Map" y "Stop LocServ", y en el XAML, verás los manejadores especificados para el evento Click de estos botones, llamados trackMe_Click y startStop_Click respectivamente. 

 

Estos dos métodos tienen la tarea de activar o desactivar el servicio de ubicación, y cambiando el valor booleano de trackingOn para que watcher_PositionChanged actualice o no el objeto Map para mostrar la posición actual del dispositivo.  Adicionalmente, se harán algunas ligeras modificaciones en la interfaz de usuario para cambiar el texto de los botones y proporcionar un mensaje acerca del estado.

 

Una llamada interesante es hecha en trackMe_Click  hacia el objeto Map.  Si el usuario especifica que le gustaría ver su posición actual en el mapa, el nivel  de zoom del mapa es modificado de 1.0 (zoom hacia afuera para mostrar todo el planeta) a 16.0 (zoom hacia adentro para que calles estén mapeadas y con nombre).

 

La activación del servicio de ubicación vuelve a hacerse en un hilo secundario, utilizando nuevamente startLocServInBackground.  El resultado de estos dos métodos se visualiza de la siguiente manera:

C#

private void trackMe_Click(object sender, RoutedEventArgs e)

{

if (trackingOn)

{

trackMe.Content = "Track Me On Map";

trackingOn = false;

myMap.ZoomLevel = 1.0f;

}

else

{

trackMe.Content = "Stop Tracking";

trackingOn = true;

myMap.ZoomLevel = 16.0f;

}

}

private void startStop_Click(object sender, RoutedEventArgs e)

{

if (startStop.Content.ToString() == "Stop LocServ")

{

startStop.Content = "Start LocServ";

statusTextBlock.Text = "Location Services stopped…";

watcher.Stop();

}

else if (startStop.Content.ToString() == "Start LocServ")

{

startStop.Content = "Stop LocServ";

statusTextBlock.Text = "Starting Location Services…";

new Thread(startLocServInBackground).Start();

}

}

Visual Basic

Private Sub trackMe_Click(sender As Object, e As RoutedEventArgs)

If trackingOn Then

trackMe.Content = "Track Me On Map"

trackingOn = False

myMap.ZoomLevel = 1F

Else

trackMe.Content = "Stop Tracking"

trackingOn = True

myMap.ZoomLevel = 16F

End If

End Sub

Private Sub startStop_Click(sender As Object, e As RoutedEventArgs)

If startStop.Content.ToString() = "Stop LocServ" Then

startStop.Content = "Start LocServ"

statusTextBlock.Text = "Location Services stopped…"

watcher.[Stop]()

Else If startStop.Content.ToString() = "Start LocServ" Then

startStop.Content = "Stop LocServ"

statusTextBlock.Text = "Starting Location Services…"

New Thread(startLocServInBackground).Start()

End If

End Sub

 

Por último, está el método watcher_PositionChanged que maneja el evento PositionChanged. Este método recibe información sobre la posición actual del dispositivo del objeto GeoPositionChangedEventArgs, que es pasado como un argumento.  Este objeto contiene información sobre la longitud del dispositivo, latitud, velocidad (en metros por segundo), el curso / dirección (un valor de punto flotante de grado que va de 0 a 360), e incluso la altitud (en metros sobre el nivel del mar).  Arrojaremos todo esto a la misma pantalla en los TextBlocks que hicimos anteriormente.

 

Además, si el usuario ha pulsado el  botón "Track Me On Map", entonces trackingOn se establece en "true" y el mapa es enfocado a nivel de la calle, así que en watcher_PositionChanged  comprobamos el valor de trackingOn el valor y centramos el mapa a nuestra posición actual si ese valor se establece en "true".  El método resultante es el siguiente:

C#

void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)

{

// Actualizar las lecturas de TextBlock

latitudeTextBlock.Text = e.Position.Location.Latitude.ToString("0.0000000000000");

longitudeTextBlock.Text = e.Position.Location.Longitude.ToString("0.0000000000000");

speedreadout.Text = e.Position.Location.Speed.ToString("0.0") + " meters per second";

coursereadout.Text = e.Position.Location.Course.ToString("0.0");

altitudereadout.Text = e.Position.Location.Altitude.ToString("0.0");

// Actualizar el mapa si el usuario ha pedido hacer un seguimiento.

if (trackingOn)

{

// Centra el pushpin y el mapa en la posición actual

myPushpin.Location = e.Position.Location;

myMap.Center = e.Position.Location;

// Si esta es la primera vez que myPushpin se traza, que intriga!

if (myMap.Children.Contains(myPushpin) == false) {myMap.Children.Add(myPushpin);};

}

}

Visual Basic

Private Sub watcher_PositionChanged(sender As Object, e As GeoPositionChangedEventArgs(Of GeoCoordinate))

Actualiza las lecturas de TextBlock

latitudeTextBlock.Text = e.Position.Location.Latitude.ToString("0.0000000000000")

longitudeTextBlock.Text = e.Position.Location.Longitude.ToString("0.0000000000000")

speedreadout.Text = e.Position.Location.Speed.ToString("0.0") & " meters per second"

coursereadout.Text = e.Position.Location.Course.ToString("0.0")

altitudereadout.Text = e.Position.Location.Altitude.ToString("0.0")

Actualizar el mapa si el usuario ha pedido hacer un seguimiento.

If trackingOn Then

Centra el pushpin y el mapa en la posición actual

myPushpin.Location = e.Position.Location

myMap.Center = e.Position.Location

Si esta es la primera vez que myPushpin se traza, que intriga!

If myMap.Children.Contains(myPushpin) = False Then

myMap.Children.Add(myPushpin)

End If

End If

End Sub

 

El tutorial se ha completado, y tienes un ejemplo de un programa que está estructurado para responder a la inicialización síncrona del servicio de ubicación, para realizar un seguimiento del estado actual del servicio de ubicación (que está sujeto a un GPS y la calidad de la señal celular), y también para trazar información de posición en un mapa de Bing que descarga bajo demanda imágenes de calle e imágenes satelitales.

 

Consideraciones Finales

·         En este tutorial usamos el ajuste de alta precisión, el cual es muy pesado en el uso de la batería.  Considera utilizar GeoPositionAccuracy.Default cuando sea posible, por ejemplo, cuando tu aplicación solo está buscando en las cercanías.

·         El ajuste MovementThreshold es también una clave para el consumo de batería, ya que en general, los datos de posición son algo ruidosos y la aplicación no debe responder igual a todos los datos de fluctuación.  Si el evento PositionChanged está disparando con demasiada frecuencia, la duración de la batería y el tiempo de procesamiento se pueden desperdiciar.

·         Debido a que el servicio de ubicación utiliza una combinación de Wi-Fi, celular, y datos GPS, los datos de ubicación se obtienen más y más precisos después de que el servicio de ubicación ha sido iniciado y ha recibido datos por un tiempo.  La información de la red Wi-Fi y celular normalmente se recibe en pocos segundos, mientras que los datos GPS pueden tardar hasta un par de minutos.

·         El objeto GeoCoordinateWatcher dispara eventos en el hilo de la interfaz de usuario. Esto significa que querrás hacer el menor trabajo posible en los manejadores de eventos PositionChanged y StatusChanged, o cualquier otro evento  de GeoCoordinateWatcher.  Si se necesita un procesamiento intenso cuando estos eventos son disparados, haz que los manejadores de eventos disparen hilos secundarios  que hagan el trabajo pesado para que tu interfaz de usuario no se congele.

Desarrollando con la cámara de Windows Phone

June 20th, 2011 7 comments

Desarrollando con la cámara de Windows Phone

Este artículo es una traducción del artículo original encontrado en: http://create.msdn.com/en-US/education/quickstarts/Developing_with_the_Windows_Phone_Camera.

 

Silverlight para Windows Phone incluye varias herramientas de fácil uso para la cámara y el uso de fotos.  Aquí vamos a mostrar cómo tomar y guardar fotos con la cámara de Windows Phone y seleccionar y mostrar fotos de la galería interna de Windows Phone.

 

Este artículo se divide en las siguientes secciones:

 

·         Creando una interfaz de usuario para la cámara y visualización de fotos

·         Tomando, seleccionando y visualizando imágenes

·         Guardando imágenes en la Biblioteca de Imágenes

 

Descarga el código fuente completo de este tutorial, hospedado en la galería de código de  Silverlight para Windows Phone.

 

Creando una interfaz de usuario para la cámara y visualización de fotos

Inicia Visual Studio y comienza un proyecto de tipo "Silverlight para Windows Phone".  A continuación, crea una interfaz de usuario (UI) que tiene los siguientes elementos:

·         Dos campos TextBlock - uno con un nombre significativo que mostrará los mensajes de estado y una etiqueta TextBlock que dice simplemente: "Desconecte el teléfono del software de Zune para ejecutar!".

·         Un Image con un nombre significativo que tendrá su fuente dinámicamente actualizada para reflejar la nueva imagen que fue tomada o elegida.

·         Tres botones con nombres significativos que se utilizarán para tomar una nueva foto, mostrar una foto existente, y guardar en el almacenamiento del teléfono la foto mostrada.  En este artículo, estos botones se llaman takePhotoButton, choosePhotoButton y savePhotoButton, respectivamente.

Una distribución propuesta de estos elementos se muestra a continuación:

clip_image002

XAML

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<Button Content="Take Photo" Height="72" HorizontalAlignment="Left"

Margin="12,6,0,0" Name="button1" VerticalAlignment="Top"

idth="189" Click="button1_Click" />

<Image Height="308" HorizontalAlignment="Left" Margin="27,275,0,0"

Name="myImage" Stretch="Fill" VerticalAlignment="Top"

Width="406"/>

<Button Content="Choose Existing" Height="72" HorizontalAlignment="Left"

Margin="194,6,0,0" Name="button2" VerticalAlignment="Top"

Width="239" Click="button2_Click" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="27,162,0,0"

Name="textBlock1" Text="Disconnect phone from Zune software to run!"

VerticalAlignment="Top" Width="406" />

<Button Content="Save Current Photo to Library" Height="72"

HorizontalAlignment="Left" Margin="12,84,0,0" Name="savePhotoButton"

VerticalAlignment="Top" Width="419" IsEnabled="False"

Click="savePhotoButton_Click" />

<TextBlock Height="71" HorizontalAlignment="Left" Margin="29,197,0,0"

Name="statusText" Text="" VerticalAlignment="Top" Width="402"

Foreground="Red" TextWrapping="Wrap" />

</Grid>

 

Como último paso antes de la codificación, agrega una referencia a Microsoft.Xna.Framework. Vamos a usar el espacio de nombres Microsoft.Xna.Framework.Media en este ensamblado con el fin de guardar las imágenes en la biblioteca de medios del teléfono, y éste debe ser referenciado por tu proyecto antes que cualquiera de sus tipos, eventos o métodos sean utilizados en tu aplicación.

 

Para agregar Microsoft.Xna.Framework en tu aplicación:

·         En el Explorador de soluciones, haz derecho en el nodo References en tu proyecto y a continuación, selecciona Add Reference.

·         Selecciona Microsoft.Xna.Framework de la lista y a continuación haz clic en OK.

 

Tomando, Seleccionando y visualizando imágenes

En el Explorador de soluciones, abre el archivo MainPage.xaml.cs, y agrega las siguientes líneas de código en la parte superior de la página, dejando las referencias por defecto en su lugar.

C#

using Microsoft.Phone.Tasks; using System.Windows.Media.Imaging; using System.IO; using System.IO.IsolatedStorage; using Microsoft.Xna.Framework.Media;

 

Esto le da acceso a tu código a los espacios de nombres necesarios para abrir la aplicación de la cámara en el teléfono y tomar una imagen, usar un objeto de mapa de bits de re-escritura para almacenar los datos de la imagen temporal, usar un stream de memoria para convertir la imagen en un archivo, guardar la imagen en el almacenamiento interno del teléfono, y mover una imagen del almacenamiento aislado del teléfono a la biblioteca multimedia del teléfono, respectivamente.

 

La selección de fotos y el uso de la cámara requerirán la coordinación entre algunos métodos, así que vamos a añadir algunos miembros de datos a la clase principal.  Dos de ellos serán objetos Selectores, que permiten a las aplicaciones ceder el control a la funcionalidad integrada en el sistema operativo del teléfono a fin de facilitar las cosas como la elección de un contacto de una lista, tomar una foto, o seleccionar una foto de la galería de fotos del teléfono.  Otro será una imagen de mapa de bits que se estará utilizando para almacenar la información de la imagen temporal, es decir, imágenes que hemos elegido ya sea desde la galería en el teléfono o simplemente tomadas con la cámara.

C#

public partial class MainPage : PhoneApplicationPage

{

// Declarar el objeto CameraCaptureTask con ámbito de la página.

CameraCaptureTask cameraCaptureTask;

PhotoChooserTask photoChooserTask;

BitmapImage bmp;

 

cameraCaptureTask y photoChooserTask van a necesitar conectar los manejadores de eventos que se disparan cuando se toma una fotografía o cuando se elige de la  biblioteca de imágenes del teléfono, respectivamente.  Esto significa que los dos eventos deben ser manejados:

  1. Evento Completed de cameraCaptureTask.
  2. Evento Completed de photoChooserTask.

Este tutorial tiene una peculiaridad: porque en ambos casos sólo queremos mostrar la imagen en pantalla, y porque los eventos Completed envían el mismo tipo de objeto a sus manejadores (un PhotoResult), usaremos un método para manejar ambos eventos.  Vamos a llamar a este método photoCaptureOrSelectionCompleted, y obtendrá la foto que ha sido tomada por la cámara o seleccionada de la biblioteca de imágenes, y la mostrará en la pantalla.  La conexión de ambos eventos Completed para este nuevo método se realiza en la función de inicio de la página, MainPage, dando como resultado lo siguiente:

C#

 

public MainPage()

{

InitializeComponent();

// Inicializa los objetos Selectores y asigna los manejadores para los eventos "Completed"

cameraCaptureTask = new CameraCaptureTask();

cameraCaptureTask.Completed += new EventHandler<PhotoResult>(photoCaptureOrSelectionCompleted);

photoChooserTask = new PhotoChooserTask();

photoChooserTask.Completed += new EventHandler<PhotoResult<(photoCaptureOrSelectionCompleted);

}

 

Anteriormente, cuando creamos la interfaz de usuario, agregamos un Image llamado myImage en la pantalla, pero no estableció su propiedad Source, dejándola en blanco.  En photoCaptureOrSelectionCompleted, sabemos que el usuario ha tomado o seleccionado una imagen así que es momento de establecer la propiedad Source de myImage a esa imagen, después escalar la imagen de modo que quepa la zona de visualización de myImage.  También actualizaremos el TextBlock statusText si es necesario.  Por último, vamos a activar el botón que permite al usuario guardar la imagen mostrada.

 

La propiedad Stretch del objeto Image determina cómo la imagen será escalada para ajustarla a las dimensiones de myImage; utilizaremos Stretch.Uniform para preservar la relación de aspecto de la imagen original.

 

Así que podemos reservar la opción de guardar esta imagen si el usuario lo desea, utilizando el mapa de bits que hemos creado antes, llamado bmp, para recibir los datos de esta nueva imagen, entonces lo asignaremos a la propiedad Source de myImage de modo que se muestre en la pantalla.  (En otro método que implementaremos después, el contenido de bmp se puede guardar en el almacenamiento interno del teléfono). El aspecto final de photoCaptureOrSelectionCompleted será así:

C#

void photoCaptureOrSelectionCompleted(object sender, PhotoResult e)

{

if (e.TaskResult == TaskResult.OK)

{

bmp = new BitmapImage();

bmp.SetSource(e.ChosenPhoto);

myImage.Source = bmp;

myImage.Stretch = Stretch.Uniform;

// Intercambio los estados de los elementos en la IU

savePhotoButton.IsEnabled = true;

statusText.Text = "";

}

else

{

savePhotoButton.IsEnabled = false;

statusText.Text = "Task Result Error: " + e.TaskResult.ToString();

}

}

Ahora conectamos los botones que colocamos en la interfaz de usuario para iniciar un Selector que nos permitirá tomar o seleccionar una imagen.  Regresa al diseñador de la interfaz de usuario y haz doble clic en el botón "Take Photo".   Esto crea un manejador de evento que será disparado cuando se haga clic en el botón.  Nuestro botón se llama takePhotoButton, y sólo necesita una línea de código para iniciar el Selector.  El evento Completed se disparará cuando la foto sea tomada, manejando el resto.  El resultado es una función muy simple llamada takePhotoButton_Click:

C#

// La cámara muestra el Choosers en respuesta a un clic del botón.

private void takePhotoButton_Click(object sender, RoutedEventArgs e)

{

cameraCaptureTask.Show();

}

 

Ahora haz doble clic en el botón "Choose Existing", que nombramos choosePhotoButton.  Una vez más, es sólo una línea de código para iniciar el Selector que selecciona una foto, lo que resulta en un choosePhotoButton_Click que tiene este aspecto:

C#

// El selector de foto en respuesta a un clic del botón

 private void choosePhotoButton_Click(object sender, RoutedEventArgs e)

{

photoChooserTask.Show();

}

 

Ahora la aplicación es capaz de capturar y seleccionar imágenes existentes y mostrarlas en la pantalla en su relación de aspecto correcto.

Como la advertencia en la interfaz de usuario dice, el teléfono debe estar desconectado del software de Zune para que los Selectores sean lanzados correctamente.

 

Guardando imágenes en la Biblioteca de Imágenes

Con el fin de guardar la imagen a la biblioteca de imágenes del teléfono, debe ser primero codificada como un JPEG mediante la clase Extensions del espacio de nombres System.Windows.Media.Imaging.  Entonces, el ensamblado XNA que hemos importado se utilizará para usar la clase MediaLibrary, cuyo método SavePicture finalmente escribe la imagen a la biblioteca de imágenes del teléfono, donde puede ser sincronizada con la computadora, visualizada en una presentación, etc.

 

Debido a que este proceso implica ambos pasos: guardar la imagen como JPEG y luego importarla a la biblioteca, vamos a escribir un archivo JPEG temporal en el almacenamiento interno del teléfono, conocido como el Almacenamiento Aislado.  Entre otras cosas, el Almacenamiento Aislado para Windows Phone asigna un espacio exclusivo y seguro de archivos para cada aplicación en el teléfono.  No vamos a entrar en detalles aquí con el uso del Almacenamiento Aislado, sólo tenemos que utilizar el espacio de almacenamiento de nuestra aplicación para escribir nuestro archivo JPEG temporal.  Se trata de crear primero un archivo vacío, luego asignarle contenido.  El tipo WriteableBitmap será usado para esta tarea, recibiendo el contenido de bmp, nuestros datos de imagen que creamos con anterioridad.  Por último, queremos actualizar el Textblock statusText cuando tenemos un resultado al guardar la imagen.

 

Regresa al diseñador de la interfaz de usuario y haz doble clic en el botón "Save Current Photo to Library", al que llamamos savePhotoButton.  Al igual que con los otros botones, esto conecta un manejador de eventos en blanco al evento Click en el botón.  Una vez implementado para cubrir todas las funcionalidades descritas, la versión final de savePhotoButton_Click se verá así:

 

 

 

private void savePhotoButton_Click(object sender, RoutedEventArgs e)

{

try

{

// Crea un nombre de archivo para el archivo JPEG en el almacenamiento aislado.

String tempJPEG = "TempJPEG";

// Crea el almacenamiento virtual y el stream del archivo. Compruebe si hay archivos duplicados tempJPEG.

var myStore = IsolatedStorageFile.GetUserStoreForApplication();

if (myStore.FileExists(tempJPEG))

{

myStore.DeleteFile(tempJPEG);

}

IsolatedStorageFileStream myFileStream = myStore.CreateFile(tempJPEG);

/ / Se crea un stream del archivo JPEG.
/ / En lugar de MyQuickApp en la URI, utilice el nombre de proyecto correcto.
/ / El uso de TempJPEG se estableció anteriormente.

Uri uri = new Uri("MyQuickApp;component/TempJPEG.jpg", UriKind.Relative);

// Crear un nuevo objeto WriteableBitmap y establece el stream de JPEG.

WriteableBitmap wb = new WriteableBitmap(bmp);

/ / Codifica un objeto WriteableBitmap a un stream  JPEG.
/ / SaveJpeg (mapa de bits WriteableBitmap, targetStream Stream, targetWidth int,
/ / targetHeight int, int orientación, la calidad int)
Extensions.SaveJpeg(wb, myFileStream, wb.PixelWidth, wb.PixelHeight, 0, 85);

myFileStream.Close();

/ Se crea un nuevo stream en el almacenamiento aislado, y guarda el archivo JPEG
/ / en la biblioteca de medios de Windows Phone.

myFileStream = myStore.OpenFile(tempJPEG, FileMode.Open, FileAccess.Read);

MediaLibrary library = new MediaLibrary();

Picture pic = library.SavePicture("SavedPicture.jpg", myFileStream);

myFileStream.Close();

savePhotoButton.IsEnabled = false;

statusText.Text = "Saved!";

}

catch (Exception myError)

{

statusText.Text = myError.Message;

}

}

 

Este tutorial se ha completado, y ahora tienes un ejemplo de un programa que controla la entrada de la cámara, además de leer y escribir en la biblioteca de fotos.  Recuerda desconectar el teléfono del software Zune para que los Selectores en el método Start se puedan ejecutar.

Detección de Movimiento (acelerómetro)

June 20th, 2011 1 comment

Detección de Movimiento (acelerómetro)

Este artículo es una traducción del artículo original encontrado en: http://create.msdn.com/en-US/education/quickstarts/Detect_Movement_%28Accelerometer%29

 

 

Silverlight para Windows Phone incluye un espacio de nombres que proporciona control y monitoreo en tiempo real del acelerómetro del teléfono.  El acelerómetro mide la intensidad y la dirección de la fuerza de aceleración que experimenta el teléfono.  Para facilitar la lectura de intensidad, un valor decimal es devuelto cuyo valor oscilará entre -1.0 y 1.0.  Esta lectura de intensidad es proporcionada por los ejes X, Y y Z del teléfono, y monitorea la fuerza de aceleración que experimenta a lo ancho, a lo largo, y en la profundidad, respectivamente.  Para determinar la dirección de la fuerza de aceleración, estos valores deben ser comparados entre sí.  Aunque el tema de dirección no está cubierto por este tutorial, cubriremos cómo registrar las lecturas del acelerómetro para que estas comparaciones puedan hacerse con mayor facilidad cuando estés utilizando el acelerómetro en tu aplicación o juego.

Este tutorial es una aplicación de Silverlight para Windows Phone que recibe la entrada del dispositivo de Windows Phone 7, y grafica las lecturas visualmente en un canvas.  Este tutorial contiene las siguientes secciones.

·         Creando una interfaz de usuario para la lectura del acelerómetro.

·         Obteniendo las entradas del acelerómetro en tiempo real.

·         Trazando los datos del acelerómetro como un gráfico.

Descarga el código fuente completo de este tutorial, hospedado en la galería de código de  Silverlight para Windows Phone.

Video Tutorial

Para ver un ejemplo de este tutorial ejecutándose en un teléfono, y para construir este tutorial siguiendo un vídeo en lugar de leer este artículo, puedes ver el siguiente video.  La página de este vídeo en Channel 9 tiene varias opciones de descarga si deseas una versión de alta definición, o si deseas descargar una versión que pueda reproducirse en otros dispositivos.

Creando una interfaz de usuario para la lectura del acelerómetro


Con el fin de mostrar las lecturas actuales del acelerómetro de un modo significativo, es muy útil mostrar tanto el valor actual (en forma numérica) y los valores recientes (en forma de gráfico).  Para ello, crea una interfaz de usuario que tenga los siguientes elementos:

·         3 TextBlock con nombres significativos, para la lectura numérica de los ejes X, Y y Z.

·         Un Canvas con un nombre significativo, sobre el cual vamos a colocar pequeños rectángulos para trazar la gráfica.

·         Un Button con un nombre significativo, que se usará para iniciar y detener el acelerómetro.

·         TextBlocks según sea necesario para facilitar el etiquetado de la información de la lectura.

·         3 Rentangles que son rellenos de diferentes colores sólidos, proporcionando una leyenda visual representando los ejes de las líneas des gráfico.

Una distribución propuesta de estos elementos se indica a continuación:

clip_image002

XAML

<Grid x:Name="LayoutRoot" Background="Transparent">

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<!–TitlePanel contiene el nombre de la aplicación y el título de la página–>

<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">

<TextBlock x:Name="ApplicationTitle" Text="JoMul’s Demo"

    Style="{StaticResource PhoneTextNormalStyle}"/>

<TextBlock x:Name="PageTitle" Text="Accelerometer" Margin="9,-7,0,0"

    Style="{StaticResource PhoneTextTitle1Style}"/>

</StackPanel>

<!–ContentPanel – coloque el contenido adicional aqui–>

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<TextBlock Height="30" HorizontalAlignment="Left" Margin="46,20,0,0"

 Name="textBlock1" Text="X:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="46,56,0,0"

 Name="textBlock2" Text="Y:" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="47,92,0,0"

 Name="textBlock3" Text="Z:" VerticalAlignment="Top" />

<Rectangle Height="20" HorizontalAlignment="Left" Margin="18,25,0,0"

    Name="rectangle1" Fill="Red" StrokeThickness="1"

 VerticalAlignment="Top" Width="16" />

<Rectangle Fill="Blue" Height="20" HorizontalAlignment="Left"

Margin="18,60,0,0" Name="rectangle2" StrokeThickness="1"

VerticalAlignment="Top" Width="16" />

<Rectangle Fill="Green" Height="20" HorizontalAlignment="Left"

Margin="18,95,0,0" Name="rectangle3" StrokeThickness="1"

VerticalAlignment="Top" Width="16" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="82,20,0,0"

    Name="xreadout" Text="1.0" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="82,56,0,0"

     Name="yreadout" Text="1.0" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="82,92,0,0"

     Name="zreadout" Text="1.0" VerticalAlignment="Top" />

<Button Content="PAUSE" Height="97" HorizontalAlignment="Left"

Margin="143,25,0,0" Name="PlayOrPause" VerticalAlignment="Top"

Width="285" Click="PlayOrPause_Click" />

<Canvas Height="400" HorizontalAlignment="Left" Margin="18,140,0,0"

   Name="Log" VerticalAlignment="Top" Width="400"

Background="White" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="419,326,0,0"

      Name="textBlock4" Text="0" VerticalAlignment="Top" Width="30" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="419,128,0,0"

      Name="textBlock5" Text="1.0" VerticalAlignment="Top" />

<TextBlock Height="30" HorizontalAlignment="Left" Margin="419,526,0,0"

      Name="textBlock6" Text="-1.0" VerticalAlignment="Top" />

</Grid>

</Grid>

 

Obteniendo las entradas del acelerómetro en tiempo real
Silverlight para Windows Phone utiliza el ensamblado Microsoft.Devices.Sensors para manejador la entrada del acelerómetro, por lo que debe referenciarse en tu proyecto antes de utilizar cualquiera de sus tipos, eventos o métodos. 

Para agregar Microsoft.Devices.Sensors en tu aplicación:

1.       En el Solution Explorer, haz clic derecho en el nodo References  de tu proyecto, a continuación, selecciona Add Reference.

2.       Selecciona Microsoft.Devices.Sensors de la lista, y a continuación haz clic en OK.

3.       Agrega el siguiente código al principio de cualquier archivo de código fuente que utilice las clases y métodos del acelerómetro.

C#

using Microsoft.Devices.Sensors;

 

El siguiente paso consiste en agregar un miembro de datos de tipo Accelerometer a la clase cuyos métodos utilizarán los datos de entrada.

 

C#

 

public partial class MainPage : PhoneApplicationPage

{

// Constructor

Accelerometer accelerometer = new Accelerometer();

 

Este miembro de datos debe ser a nivel de clase porque al menos dos métodos deben estar involucrados en la lectura de entrada del acelerómetro:

 

·         Un manejador de evento que se llama cuando el acelerómetro dispara el evento ReadingChanged.

·         Un método que contiene una declaración para adjuntar el manejador al evento ReadingChanged.

 

Comencemos con el primero.  Todos los manejadores de eventos aceptan por lo menos dos de los siguientes argumentos: un objeto genérico que hace referencia al objeto que disparó el evento (en este caso, el miembro de datos Accelerometer), y un "event args" personalizado cuyas propiedades puedan ser interpretadas para acceder a los datos generados por el evento. Nuestro manejador para el evento ReadingChanged del acelerómetro comenzará de esta manera:

 

C#

void myHandler(object sender, AccelerometerReadingEventArgs e)

{

// TODO: Código aquí

}

 

Ahora tenemos que iniciar el acelerómetro y conectar el evento ReadingChanged a myHandler, y para los fines de este tutorial, hacerlo en la función principal está bien.

 

C#

public MainPage()

{

InitializeComponent();

accelerometer.Start();

accelerometer.ReadingChanged += new

EventHandler<AccelerometerReadingEventArgs>(myHandler);

}

 

Es aquí donde tenemos un pequeño contratiempo.  Tenemos que actualizar la interfaz de usuario con los datos de nuestro acelerómetro, sin embargo, el evento ReadingChanged se dispara en el hilo del acelerómetro, y así myHandler se ejecutará en ese hilo también.  Sin embargo, queremos que myHandler actualice la interfaz de usuario con las lecturas del acelerómetro y la interfaz de usuario se ejecuta en su propio hilo, por lo que es inaccesible.  Afortunadamente, la solución es una sola línea que utiliza el objeto Dispatcher para invocar una función en el hilo de la interfaz de usuario que puede hacer la actualización para nosotros, pasando el objeto AccelerometerReadingEventArgs que contiene las lecturas que queremos mostrar.  Vamos a llamar a esta función, updateMyScreen.  myHandler ahora se ve así:

 

C#

void myHandler(object sender, AccelerometerReadingEventArgs e)

{

Deployment.Current.Dispatcher.BeginInvoke(() => updateMyScreen(e));

}

 

Ahora estás listo para llevar las lecturas del acelerómetro a la interfaz de usuario.  El objeto AccelerometerReadingEventArgs nos permite hacer fácilmente esto a través de sus propiedades que contienen las lecturas actuales de los ejes X, Y y Z.  Terminamos esta sección mediante la implementación de una pantalla muy simple de los datos del acelerómetro: una lectura de texto en la interfaz de usuario.  updateMyScreen, que se ejecuta en el hilo de la  interfaz de usuario y que se llama cada vez que se dispara el evento ReadingChanged, sólo necesita actualizar la propiedad Text de los elementos del TextBlock.

C#

void updateMyScreen(AccelerometerReadingEventArgs e)

{

// Actualiza los Textblocks

xreadout.Text = e.X.ToString("0.00");

yreadout.Text = e.Y.ToString("0.00");

zreadout.Text = e.Z.ToString("0.00");

}

 

 

El objeto AccelerometerReadingEventArgs expresa la fuerza de aceleración que se experimenta en los ejes X, Y y Z como un valor Double (punto flotante numérico).  Estos valores se convierten en una cadena con precisión decimal de dos puntos mediante el método ToString y pasando el argumento de formato como "0.00".

 

En este punto, podrías construir la aplicación y ejecutarla para ver en la pantalla los datos del acelerómetro.  Sin duda los fundamentos han sido mostrados.  Sin embargo, este tutorial incluye código que traza los datos en una gráfico usando los elementos Rectangle y Canvas que has puesto en la interfaz de usuario anteriormente, lo que te ayudará a ver realmente lo que el acelerómetro está haciendo cuando intentes utilizar los datos en tus aplicaciones.  Es altamente recomendable que continúes, sin embargo, si sólo quieres tener acceso a los datos en bruto, puedes detenerte aquí.

 

Trazado de los datos del acelerómetro como un gráfico
El elemento Rectangle de la interfaz de usuario está listo para ser usado como un pixel, lo que hace que esta tarea sea más sencilla de lo que se podría esperar.  Un gráfico en este caso simplemente será una serie de rectángulos colocados cuidadosamente que se le asignan colores mediante el uso de la propiedad Fill.  Vamos a "pintar" estos rectángulos en el gran Canvas blanco que colocamos en la interfaz de usuario en la primera sección.  Las propiedades Top y Left del rectángulo determinarán su posición en el Canvas, e incluso podemos hacerlas relativas al Canvas referenciando al Canvas en el método SetValue del rectángulo.

 

En el gráfico, trazamos tres líneas de colores diferentes, cada una representando un eje del acelerómetro.  Estas líneas se representan como elementos adyacentes visuales del Rectangle. Para cada uno de estos rectángulos, se utilizan dos piezas de datos para trazar la posición del rectángulo: la cantidad de tiempo que ha pasado, que vamos a rastrear con un iterador genérico que incrementaremos en 1, y por supuesto la lectura del  acelerómetro que obtenemos con el objeto AccelerometerReadingEventArgs.

 

El evento ReadingChanged maneja de la progresión de la gráfica, tal como lo llevó a la representación textual de estos datos en la sección anterior.  El evento ReadingChanged se dispara solo si mientras el estado del acelerómetro sea "started" (iniciado), después de llamar al la función Start del Accelerometer.  Esto sucede en sincronización con el ciclo nativo de actualización de la aplicación (30 cuadros por segundo, por defecto), y es así muy fiable, como el gráfico demostrará visualmente.

 

Como es de esperar, el trazado del gráfico necesita realizarse en el hilo de la interfaz de usuario, por lo que queremos extender updateMyScreen.  Antes de hacer eso, vamos a empezar con la parte fácil: establecer el iterador.  Obviamente este iterador tendrá que estar fuera del ámbito de updateMyScreen, por lo que hacerlo un miembro de datos para la clase, junto con el objeto Accelerometer, será suficiente:

C#

public partial class MainPage : PhoneApplicationPage

{

// Constructor

Accelerometer accelerometer = new Accelerometer();

double iterator = 0;

 

Hacemos el iterador de tipo Double para evitar el desperdicio de los ciclos del CPU del teléfono y convertirlo en una posición en el Canvas más tarde.  Se seguirá iterando en 1, que es todo lo se requiere.  A medida que se incrementa en 1, la posición horizontal que asignamos al elemento Rectangle en el gráfico se desplaza a la derecha por 1 pixel, permitiendo la colocación de los pixeles en la pantalla para trazarlos de izquierda a derecha en la pantalla con el paso del tiempo, haciendo una línea.

 

Nota                       
De aquí en adelante, es importante tener en cuenta que se asume un Canvas de 400×400.

 

Ahora extendemos updateMyScreen para hacer el dibujo. Esto se hace en algunas fases:

1.  Convierte la lectura del acelerómetro (que va desde -1.0 a 1.0 y tiene un punto medio de 0) en una posición vertical en el Canvas para el Rectangle en uso (que va desde el bajo de 400 a lo alto de 0 y tiene un punto medio de 200).  Con lo que respecta a iterator, el valor resultante se mantendrá como un doble para que el objeto Canvas pueda utilizarlo.

2.       Los elementos Rectangle que se utilizarán como los pixeles que constituyen las líneas del gráfico necesitan ser creados, con un tamaño de un pixel y asignado colores únicos, antes de que sus posiciones sean trazadas.  Tenemos tres rectángulos nuevos por cada actualización de ReadingChanged, cada uno representando uno de los tres ejes del acelerómetro.

3.       El valor del acelerómetro convertido en el paso 1 se utiliza para la posición vertical del Rectangle en el Canvas, y el iterator se utiliza para la posición horizontal del Rectangle en el Canvas.  Estos son pasados usando el método SetValue del rectángulo.

4.       Los tres nuevos rectángulos son pintados sobre el Canvas haciendo los rectángulos "hijos" en el Canvas.  Esto se hace con la función Add de la propiedad Children del Canvas.

5.       Dependiendo de si estás fuera del espacio horizontal en el Canvas (es decir, iterator ha alcanzado el valor de 399), ya sea que borres el Canvas y comiences de nuevo desde el lado izquierdo (limpiando la propiedad Children del Canvas y estableciendo iterator de nuevo a cero), o simplemente incrementas el iterador en 1.

El updateMyScreen resultante tiene este aspecto:

C#

void updateMyScreen(AccelerometerReadingEventArgs e)

{

// Actualiza los textblocks

xreadout.Text = e.X.ToString("0.00");

yreadout.Text = e.Y.ToString("0.00");

zreadout.Text = e.Z.ToString("0.00");

//Dibuja en el canvas:

double currentXOnGraph = Math.Abs((e.X * 200) – 200);

double currentYOnGraph = Math.Abs((e.Y * 200) – 200);

double currentZOnGraph = Math.Abs((e.Z * 200) – 200);

Rectangle xPoint = new Rectangle();

Rectangle yPoint = new Rectangle();

Rectangle zPoint = new Rectangle();

xPoint.Fill = new SolidColorBrush(Colors.Red);

yPoint.Fill = new SolidColorBrush(Colors.Blue);

zPoint.Fill = new SolidColorBrush(Colors.Green);

// Establece el tamaño de los pixeles

xPoint.Width = 1;

xPoint.Height = 2;

yPoint.Width = 1;

yPoint.Height = 2;

zPoint.Width = 1;

zPoint.Height = 2;

/ / Estos pixeles se "pega n" en el Canvas mediante el ajuste de su posición
/ / según los valores-gráfico CurrentX / Y / Z. Para fijar su posición
/ / relativo al Canvas, pasar la propiedades Canvas de a través de los pixeles
/ / del método SetValue. Utilice un iterador genérico para determinar la distancia
/ / de los píxel que debe estar desde el lado izquierdo del Canvas.

xPoint.SetValue(Canvas.LeftProperty, iterator);

xPoint.SetValue(Canvas.TopProperty, currentXOnGraph);

yPoint.SetValue(Canvas.LeftProperty, iterator);

yPoint.SetValue(Canvas.TopProperty, currentYOnGraph);

zPoint.SetValue(Canvas.LeftProperty, iterator);

zPoint.SetValue(Canvas.TopProperty, currentZOnGraph);

// Finalmente, asocial cada pixel con el Canvas

Log.Children.Add(xPoint);

Log.Children.Add(yPoint);

Log.Children.Add(zPoint);

if (iterator == 399)

{

Log.Children.Clear();

iterator = 0;

} else {

iterator++;

}

}

 

Por último, ya que el gráfico progresará sin fin, sin darte la oportunidad de observar los datos, debemos conectar un manejador de eventos para ese botón Play/Pause.  En Visual Studio, puedes simplemente hacer doble clic en el botón del diseñador de la interfaz de usuario y el evento OnClick será conectado a una función con nombre apropiado.  También puedes escribirlo tú mismo.  De cualquier manera, ya que el evento ReadingChanged está haciendo la actualización del gráfico por nosotros, todo lo que necesitamos hacer para implementar la funcionalidad de Play/Pause es iniciar y detener el acelerómetro.  La función resultante tiene este aspecto:

C#

private void PlayOrPause_Click(object sender, RoutedEventArgs e)

{

if (PlayOrPause.Content.ToString() == "PAUSE")

{

PlayOrPause.Content = "PLAY";

accelerometer.Stop();

} else if (PlayOrPause.Content.ToString() == "PLAY")

{

accelerometer.Start();

PlayOrPause.Content = "PAUSE";

}

}

 

Ejecutando este código se muestra la actividad de un gráfico de 3 líneas trazando la actividad del acelerómetro y una lectura de texto en tiempo real.  Naturalmente, para ver realmente cómo este código responde a la entrada del acelerómetro, necesitas desplegarlo en un dispositivo Windows Phone.  Sin embargo, hay maneras de simular la entrada del acelerómetro si esto no es posible.

Lanzadores y Selectores

June 20th, 2011 3 comments

Lanzadores y Selectores

Este artículo es una traducción del artículo original encontrado en: http://create.msdn.com/en-US/education/quickstarts/Lanzadores_and_Selectores.

 

Las aplicaciones de Silverlight para Windows Phone no tienen acceso directo a las aplicaciones incorporadas en el dispositivo, tales como marcador de teléfono, o los datos de la biblioteca del usuario, como la biblioteca de fotos. Esto se debe a que todas las aplicaciones Windows Phone están aisladas unas de otras en entornos limitados (sandboxes).  Una aplicación no puede iniciar otra aplicación, acceder a la memoria de otra aplicación, o acceder al almacenamiento de datos de otra aplicación.  Los Lanzadores y Selectores permiten a las aplicaciones de Silverlight para Windows Phone  utilizar indirectamente las aplicaciones incorporadas en el dispositivo y acceder a bibliotecas de datos comunes.  Este tutorial describe qué pueden hacer los Lanzadores y Selectores y cómo utilizarlos en tus aplicaciones.

 

Este artículo contiene las siguientes secciones:

·         Introducción a los Lanzadores y Selectores

·         Usando Lanzadores

·         Usando Selectores

 

Introducción a Lanzadores y Selectores

Los Lanzadores y Selectores permiten a las aplicaciones de Silverlight para Windows Phone acceder a las aplicaciones integradas y almacenes de datos en el dispositivo Windows Phone.  Por ejemplo, si deseas que la aplicación realice una llamada de teléfono, deberás utilizar el Lanzador PhoneCallTask ​​para iniciar la aplicación de marcador telefónico. Para acceder a las bibliotecas de datos en el dispositivo, como la biblioteca de fotos, debes utilizar el Selector PhotoChooserTask.

 

La diferencia entre los Lanzadores y Selectores, es que Lanzadores no devuelve un valor cuando finalice la aplicación iniciada, y los Selectores retornan un valor.  Por ejemplo, el Lanzador EmailComposeTask  inicia la aplicación de correo electrónico y al salir, el control se devuelve a la aplicación que llama el Lanzador. El Selector CameraCaptureTask, por el contrario, inicia la aplicación de la cámara, pero después que el usuario toma una fotografía, la aplicación de la cámara es cerrada y devuelve el valor de la foto que fue tomada.

 

Cuando llamas a un Lanzador o Selector, tu aplicación de Silverlight para Windows Phone se desactiva y la aplicación lanzada comienza.  Cuando se cierra la aplicación lanzada, tu aplicación se vuelve a activar.  Este proceso se llama tombstoning y puede tener ligeros efectos sobre el estado de tu aplicación.  Para obtener información sobre cómo manejar adecuadamente tombstoning en tu aplicación de Silverlight para Windows Phone, consulta la sección Modelo de Ejecución para Windows Phone  en MSDN y Ejecutando una Aplicación en Segundo Plano (Tombstoning).

 

Las clases de Lanzadores y Selectores están en el espacio de nombres Microsoft.Phone.Tasks, por lo que tendrás que incluir una directiva using en tu aplicación.

 

Usando Lanzadores

El proceso para utilizar todas las clases de Lanzadores es la misma.  Para utilizar un Lanzador, usa los pasos siguientes:

 

·         Crea una instancia de la clase Lanzador.

·         Establece las propiedades en el objeto Lanzador.

·         Llama al método Show.

 

Por ejemplo, para utilizar el Lanzador de correo electrónico para componer un nuevo correo electrónico, debes crear una instancia de EmailComposeTask, establecer las propiedades To, Body y Subject, y luego llamar al método Show para iniciar la aplicación. Cuando se cierra la aplicación de correo electrónico, el control se devuelve a tu aplicación.

La siguiente tabla enlista los diferentes Lanzadores disponibles:

Lanzador

Descripción

EmailComposeTask  

Permite a una aplicación lanzar la aplicación de correo electrónico desplegando un nuevo mensaje.  Utiliza esta opción para permitir a los usuarios enviar correo electrónico desde tu aplicación.

MarketplaceDetailTask

Permite a una aplicación lanzar la aplicación cliente del Windows Phone Marketplace y mostrar la página de detalles del producto especificado.

MarketplaceHubTask

Permite que una aplicación lance la aplicación cliente del Windows Phone Marketplace.

MarketplaceSearchTask

Permite que una aplicación lance la aplicación cliente del Windows Phone Marketplace y muestre los resultados de los términos de búsqueda especificados.  

MediaPlayerLauncher

Permite que una aplicación lance el reproductor de medios.

PhoneCallTask

Permite a una aplicación lanzar la aplicación de Teléfono.  Utiliza esta opción para permitir a los usuarios hacer una llamada telefónica desde tu aplicación.

SearchTask

Permite a una aplicación lanzar la aplicación de búsqueda en la web.

SmsComposeTask

Permite a una aplicación lanzar la aplicación de Mensajería.  La aplicación de mensajería se inicia con un nuevo mensaje SMS.

WebBrowserTask

Permite a una aplicación lanzar la aplicación del navegador web.

 

El siguiente ejemplo muestra cómo utilizar el Lanzador PhoneCallTask para abrir el marcador de teléfono en el dispositivo.  Primero, una interfaz de usuario básica es creada, la cual tiene un Button para llamar al Lanzador.

XAML

<Button Name="ButtonDialer"

Content="Place Call"

Height="100" Width="200"

Click="ButtonDialer_Click" />

 

La imagen siguiente muestra un ejemplo de la aplicación ejecutándose en el emulador de Windows Phone.

clip_image002

 

A continuación, un objeto PhoneCallTask es instanciado y se establecen las propiedades  PhoneNumber   y DisplayName.  Por último, el método Show es llamado para iniciar la aplicación.

C#

private void ButtonDialer_Click(object sender, RoutedEventArgs e)

{

// El lanzador

PhoneCallTask phoneCallTask = new PhoneCallTask();

// Información de contacto para pasar a la aplicación de marcador telefónico.    

phoneCallTask.PhoneNumber = "(555)-555-5555";

phoneCallTask.DisplayName = "Fred";

// Inicia la aplicación de marcador de teléfono.

phoneCallTask.Show();

}

Después que el método Show es llamado, se pide al usuario elegir en hacer o no la llamada.  La siguiente imagen muestra un ejemplo de la aplicación ejecutando en el emulador de Windows Phone.

clip_image004

Si el usuario elige realizar la llamada, la aplicación de teléfono es lanzada y el número de teléfono es marcado.  Las siguientes imágenes muestran la aplicación de ejemplo ejecutando en el emulador de Windows Phone.

clip_image006

El siguiente ejemplo muestra cómo utilizar el Lanzador SearchTask para buscar en Internet desde tu aplicación.

Primero, una interfaz de usuario básica es creada, la cual tiene un Button para llamar al Lanzador.

XAML

<Button Name="ButtonSearch"

Height="100" Width="250"

Content="Search"

Click="ButtonSearch_Click" />

 

La imagen siguiente muestra un ejemplo de la aplicación que se ejecuta en el emulador de Windows Phone.

clip_image008

Después, se crea una instancia de SearchTask y se establece la propiedad SearchQuery a "Silverlight Windows Phone".  Por último, el método Show es llamado para iniciar la aplicación.

 

C#

private void ButtonSearch_Click(object sender, RoutedEventArgs e)

{

// El lanzador

searchTask searchTask = new SearchTask();

// Establece la consulta de búsqueda

searchTask.SearchQuery = "Silverlight Windows Phone";

// Inicia la aplicación de búsqueda de teléfono.

searchTask.Show();

}

 

Después  de que método Show es llamado, se solicita al usuario un cuadro de diálogo de privacidad preguntando si desea permitir que la búsqueda proceda.  La siguiente imagen muestra la página de privacidad de la búsqueda.

 

clip_image010

 

Si el usuario acepta las condiciones, la búsqueda es ejecutada y los resultados de búsqueda aparecen.  La siguiente imagen muestra un ejemplo de la aplicación que se ejecuta en el  emulador de Windows Phone.

clip_image012

 

Usando Selectores


El uso de Selectores es muy similar al uso Lanzadores.  La principal diferencia es que los Selectores retornan valores a través del evento Completed.  Para usar un Selector, usa los siguientes pasos:

·         Crea una instancia de la clase del Selector.

·         Agrega un manejador para el evento Completed

·         Establece las propiedades en el objeto del Selector

·         Llama al método Show

·         Recupera el valor de retorno de la aplicación del Selector en el manejador del evento Completed.

Por ejemplo, para utilizar el Selector de Fotos, debes crear una instancia de la clase PhotoChooserTask, agregar un manejador para el evento Completed, llamar al método Show, y luego en el manejador Completed,  si el TaskResult es OK, recupera el stream de la imagen de la propiedad ChosenPhoto de los argumentos del evento.

La siguiente tabla enlista los diferentes Selectores que están disponibles:

Selector

Descripción

CameraCaptureTask

Permite a una aplicación  iniciar la aplicación Cámara. Utiliza esta opción para permitir a los usuarios para tomar una foto desde tu aplicación.

EmailAddressChooserTask

Permite a una aplicación iniciar la aplicación de Contactos. Utilízalo para obtener la dirección de correo electrónico de un contacto seleccionado por el usuario.

PhoneNumberChooserTask

Permite a una aplicación para iniciar la aplicación de Contactos. Utilízalo para obtener el número de teléfono de un contacto seleccionado por el usuario.

PhotoChooserTask

Permite a una aplicación lanzar la aplicación de selección de fotos.  Utilízalo para permitir a los usuarios seleccionar una foto.

SaveEmailAddressTask

Permite a una aplicación iniciar la aplicación de Contactos. Utiliza esta opción para permitir a los usuarios guardar una dirección de correo electrónico desde tu aplicación a un contacto nuevo o existente.

 

SavePhoneNumberTask

Permite a una aplicación iniciar la aplicación de Contactos. Utiliza esta opción para permitir a los usuarios guardar un número de teléfono desde tu aplicación a un contacto nuevo o existente.

 

El siguiente ejemplo muestra cómo utilizar el Selector PhoneNumberChooserTask para elegir un número de teléfono de uno de los contactos en el dispositivo.  Primero se crea una interfaz de usuario, la cual tiene un Button para llamar al Selector  y un TextBlock para mostrar el resultado.

 

XAML

<!–ContentPanel – coloque el contenido adicional aquí–>

<StackPanel>

<Button Name="ButtonChooser"

Height="150" Width="275"

Content="Get Phone Number"

Click="ButtonChooser_Click"/>

<TextBlock Name="txtPhoneNumber"

Margin="10"

FontSize="28"

Text="Phone Number: " />

</StackPanel>

 

La siguiente imagen muestra un ejemplo de  la aplicación que se ejecuta en el emulador de Windows Phone.

clip_image014

A continuación, se define una instancia global de PhoneNumberChooserTask.  En el constructor público de la clase, el PhoneNumberChooserTask  es instanciado.  Un manejador de eventos denominado numberChooser_Completed es creado para  manejar el evento Completed.  Por último, el método Show es llamado al iniciar la aplicación.

 

En el manejador del evento Completed, la propiedad TaskResult en PhoneNumberResult es verificada.  Si TaskResult es OK, la propiedad Text en el TextBlock se establece con el valor de la propiedad PhoneNumber en el objeto PhoneNumberResult.

 

C#

public partial class MainPage : PhoneApplicationPage

{

PhoneNumberChooserTask numberChooser;

// Constructor

public MainPage()

{

InitializeComponent();

numberChooser = new PhoneNumberChooserTask();

numberChooser.Completed +=

new EventHandler<PhoneNumberResult>(numberChooser_Completed);

}

void numberChooser_Completed(object sender, PhoneNumberResult e)

{

// Compruebe si TaskResult es un éxito

if (e.TaskResult == TaskResult.OK)

{

// Mostrar el número de teléfono en el TextBlock  txtPhoneNumber

txtPhoneNumber.Text += e.PhoneNumber;

}

}

private void ButtonChooser_Click(object sender, RoutedEventArgs e)

{

try

{

// Inicia el Selector.

numberChooser.Show();

}

catch (System.InvalidOperationException ex)

{

// Captura la excepción, pero no es necesario el manejo.

}

}

}

 

La siguiente imagen muestra el Selector PhoneNumber ejecutando en el emulador de Windows Phone.

clip_image016

 

Después de que el usuario selecciona el contacto para obtener el número de teléfono, el número se visualiza.  La siguiente imagen muestra la aplicación después de que un contacto es seleccionado.

clip_image018

Consumiendo servicio de datos de Windows Azure utilizando el cliente OData

June 15th, 2011 6 comments

Consumiendo servicio de datos de Windows Azure utilizando el cliente OData

Este artículo es una traducción del artículo original encontrado en: http://create.msdn.com/en-US/education/quickstarts/ODataService.

 

 

El Protocolo Open Data (OData) se basa en un modelo de entidad y relación que te permite acceder a datos en el estilo de recursos REST.  OData permite el uso del protocolo estándar HTTP para ejecutar consultas, e incluso crear, actualizar y eliminar datos de un servicio de datos remoto.  Mediante el uso de la biblioteca de cliente OData para Windows Phone, tu aplicación de Windows Phone puede consumir datos de un servicio de Windows Azure o cualquier otro servicio que soporte el protocolo OData.  La biblioteca cliente genera peticiones HTTP a un servicio de OData y transforma los datos del feed de respuesta en objetos en el cliente.

Nota

El cliente OData para Windows Phone 7 está disponible como una biblioteca independiente que se puede descargar e instalar desde la página de descarga en CodePlex Open Data Protocol—client libraries.

Este tutorial contiene las siguientes secciones:

  • Descripción de los servicios OData para Windows Phone
  • Enlazando datos a controles
  • Paginación y Navegación
  • Manteniendo el Estado de la Aplicación
  • Generando clases de datos cliente

Los ejemplos del uso de Silverlight se ejecutan en el navegador para simular su comportamiento para Windows Phone. El comportamiento real puede ser ligeramente diferente en el emulador de Windows Phone o en un dispositivo Windows Phone.

Descripción de los servicios OData para Windows Phone

Las aplicaciones de dispositivos móviles dependen en gran medida de fuentes de datos remotas, y la plataforma Windows Azure proporciona una excelente fuente de datos para tu aplicación de Windows Phone.  OData es uno de los mecanismos primarios de acceso de datos de la plataforma Windows Azure.  Varios componentes de la plataforma de Windows Azure producen feeds OData, incluyendo Almacenamiento en Tablas de Windows Azure, Microsoft SQL Azure y el Marketplace de Windows Azure.  Una lista completa de feeds públicos OData está disponible en el Sitio Web de Open Data Protocol.

También puedes utilizar los WCF Data Services para exponer tus propios datos como feeds OData que puedan ser consumidos en las aplicaciones que ejecutan en una variedad de plataformas, incluyendo Windows Phone.  Para obtener más información, consulta WCF Data Services. 

A modo de ejemplo, Netflix expone su catálogo de películas como un feed de OData basado en la nube.  Consumimos este feed OData público en el siguiente ejemplo que es la base para este tutorial:

image

Haz clic en  el mosaico OData on Phone para iniciar el ejemplo del servicio OData.  En el teléfono, cuando tocas el botón Next Page (Página siguiente) la siguiente página de datos se carga desde el servicio de datos.  Cuando tocas un elemento de la lista, se despliega la información detallada acerca del título seleccionado.  En este ejemplo, el botón Atrás trabaja como lo hace en el teléfono navegando de vuelta a la página anterior.  Puedes descargar el proyecto completo para esta aplicación Windows Phone  en el proyecto de Silverlight para Windows Phone en el sitio web de Galería de Código en MSDN.

Enlazando datos a controles

En la biblioteca de cliente OData para Windows Phone 7, la clase DataServiceCollection representa una colección dinámica de enlace de datos que proporciona notificaciones cuando los elementos se añaden o se quita de la colección.  Una consulta basada en URI determina cuáles objetos de datos la colección tendrá.  Este URI es especificado como un parámetro en el método LoadAsync de la clase DataServiceCollection.  Cuando se ejecuta, este método devuelve un feed OData que materializado en objetos de datos en la colección de enlace.  Los objetos materializados son administrados por el DataServiceContext que está asociado con la colección de enlace.  El método LoadAsync de la clase DataServiceCollection asegura que los resultados sean transportados al hilo correcto, para que no necesites utilizar el objeto Dispatcher.  Para obtener más información sobre cómo trabajar con la biblioteca cliente OData para Windows Phone 7, consulta Información general de Open Data Protocol (OData) para Windows Phone.

Debido a que las aplicaciones de Windows Phone requieren de navegación entre múltiples páginas, debes utilizar un patrón de diseño Model-View-ViewModel (MVVM) para tus aplicaciones de datos.  En este patrón, el modelo es generado por las herramientas basadas en los metadatos devueltos por el servicio de datos, la vista se compone de todos los controles enlazados en la página, y el ViewModel es un componente compartido que hace el trabajo de acceder al servicio de datos y exponer los datos que están enlazados a la vista.  Con este enfoque, puedes exponer el DataServiceContext como una propiedad de la clase del ViewModel, junto con las propiedades que regresan instancias de DataServiceCollection o cualquier otro valor dinámico que estén vinculadas a los controles en la vista.  El ViewModel también debe exponer las propiedades que necesitan ser almacenadas cuando se desactiva la aplicación, lo cual discutiremos en una sección posterior.  El siguiente diagrama de objetos representa la clase MainViewModel para este ejemplo:

El siguiente ejemplo muestra las definiciones de las propiedades en la clase MainViewModel que exponen las instancias DataServiceContext y DataServiceCollection:

C#

 

// Define la raíz URI del servicio de datos.

private static readonly Uri rootUri = new Uri("http://odata.netflix.com/v1/Catalog/");

// Define los tipos DataServiceContext.

private NetflixCatalog _context;

// Define la colección de enlaces para los títulos.

private DataServiceCollection<Title> _titles;

// Obtiene y establece la colección de Títulos de objetos de la alimentación.

public DataServiceCollection<Title> Titles

{

get { return _titles; }

private set

{

// Establecer la colección Clientes.

_titles = value;

// Registro de un controlador para la devolución de llamada LoadCompleted.

_titles.LoadCompleted += OnTitlesLoaded;

// Provoca el evento PropertyChanged.

NotifyPropertyChanged("Titles");

}

}

La clase MainViewModel se expone como una propiedad estática de la clase raíz de la aplicación (App), tal como se muestra a continuación:

C#

 

static MainViewModel _viewModel = null;

// Un ViewModel  estático utilizado para las vistas

public static MainViewModel ViewModel

{

get

{

// Retrasa la creación del modelo de vista hasta que lo necesite.

if (_viewModel == null)

{

   _viewModel = new MainViewModel();

}

return _viewModel;

}

}

El ViewModel se establece como el DataContext de la página, lo que nos permite enlazar el control ListBox en MainPage.xaml al DataServiceCollection retornado por la propiedad Titles de la clase MainViewModel.  Se puede ver en el siguiente ejemplo de XAML que el ListBox y algunos otros elementos están vinculados a las propiedades de MainViewModel:

XAML

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<ListBox Margin="0,0,-12,0" ItemsSource="{Binding Titles}"

SelectionChanged="OnSelectionChanged" Height="Auto">

<ListBox.ItemTemplate>

<DataTemplate>

<StackPanel Margin="0,0,0,17" Width="432" Orientation="Horizontal">

<Image Source="{Binding Path=StreamUri}"

Height="75" Width="50" />

<StackPanel Orientation="Vertical">

<StackPanel.Resources>

<converter:TruncateSynopsis x:Key="synopsis" />

</StackPanel.Resources>

<TextBlock Text="{Binding Path=ShortName}" TextWrapping="Wrap"

Style="{StaticResource PhoneTextLargeStyle}"/>

<TextBlock Text="{Binding Path=ShortSynopsis,

Converter={StaticResource synopsis}}"

TextWrapping="Wrap" Margin="12,-6,12,0"

Style="{StaticResource PhoneTextSubtleStyle}"/>

</StackPanel>

</StackPanel>

</DataTemplate>

</ListBox.ItemTemplate>

</ListBox>

</Grid>

<StackPanel Grid.Row="2" Orientation="Horizontal">

<TextBlock Name="PagingInfo" Text="{Binding PagesLoadedText}" Margin="12,20,10,28"

      Width="270" Style="{StaticResource PhoneTextNormalStyle}" />

<Button Name="MoreButton" Content="Next Page"

      HorizontalAlignment="Right" Width="185" Height="80" Click="MoreButton_Click" />

</StackPanel>

Cuando se carga la página MainPage.xaml, la propiedad IsDataLoaded en el ViewModel es comprobada.  Cuando los datos no están cargados, el método LoadData en el ViewModel es llamado para establecer los objetos de enlace y los títulos de petición del servicio de datos.

C#

// Se utiliza para determinar si se cargan los datos.

public bool IsDataLoaded { get; private set; }

// Carga los datos cuando la aplicación se inicializa.

public void LoadData()

{

// Instancia el contexto y la colección de enlaces.

Context = new NetflixCatalog(_rootUri);

Titles = new DataServiceCollection<Title>(Context);

// Carga los datos

Titles.LoadAsync(GetQueryUri());

}

Cuando el método LoadAsync es llamado, la biblioteca cliente envía de forma asincrónica una consulta al servicio OData que devuelve un feed Atom de entradas de tipo Title.  Cuando la respuesta es recibida, el evento LoadCompleted se dispara y las entradas en el feed son materializadas por la biblioteca cliente en objetos de la colección de títulos, que está enlazada al control ListBox.

OData define un mecanismo para acceder a datos binarios independientes de la entidad a la que pertenecen.  De esta manera, un servicio de datos puede exponer a grandes datos binarios como un recurso de medios, que pertenece a vínculo de entrada de medios.  En el catálogo de Netflix, la entidad Title es un vínculo de medios con un recurso relacionado a medios, que es el arte de la caja del título.  El método GetReadStreamUri en el ViewModel, llama al método GetReadStreamUri en el DataServiceContext para devolver la URI del recurso de los medios.  El siguiente ejemplo muestra la definición de una propiedad de extensión StreamUri que devuelve el URI del recurso de los medios para el enlace:

C#

// Extiende la clase Title para enlazar el URI de recursos

public partial class Title

{

public Uri StreamUri

{

get

{

// Obtiene el URI para los recursos de medios

return App.ViewModel.GetReadStreamUri(this);

}

}

}

 

En este ejemplo, la propiedad StreamUri llama al método GetReadStreamUri para devolver el URI del recurso de medios, que es la imagen del arte de la caja.  Cuando enlazamos la propiedad StreamUri al atributo Source de un control de Image, el URI retornado es usado descargar y mostrar el arte de la caja para cada título.

 

Recomendación

Para un vínculo de medios, te recomendamos que obtengas el URI del recurso del medio llamando GetReadStreamUri en vez de alguna otra propiedad de la entidad.  A pesar que la URI del recurso de medios funciona bien en este caso para crear una imagen en el cliente, otros métodos de DataServiceContext pueden ser usados para acceder y modificar los recursos de medios como un stream binario.

 

Paginación y navegación

En este ejemplo, el URI de la consulta es construido utilizando los parámetros de paginación  definidos en la aplicación.  En OData hay dos tipos diferentes de paginación.  Un cliente puede utilizar las opciones de consulta $top y $skip para limitar el número de entradas en la respuesta a una página lógica en lugar del feed completo.  El servicio de datos también puede limitar el número de entradas devueltas en una respuesta dada, cuando la respuesta contiene un token de continuación que se utiliza para obtener la siguiente página de datos del servicio de datos.  

 

Debido a que el cliente no es capaz de determinar si un servicio de datos implementa la paginación del servidor o incluso el tamaño de la página, debes considerar la implementación de la paginación del lado del cliente en las aplicaciones de Windows Phone para evitar que una consulta devuelva un feed muy grande, el cual puede tomar tiempo y consumir recursos valiosos en el teléfono.  También debes estar preparado para manejar la paginación del lado del servidor en tu aplicación.

 

A continuación se muestra el método GetQueryUri de este ejemplo el cual devuelve el URI para la consulta, que se crea basándose en las variables pasadas en los parámetros $top y $skip.

 

C#

// Método privado que devuelve la consulta específica para páginas.

private Uri GetQueryUri()

{

// Construye y devuelve el URI de la consulta para la siguiente página de resultados.

var queryUri = new Uri(string.Format("/Titles?$top={0}&$skip={1}",

_pageSize, _currentPage * _pageSize), UriKind.Relative);

if (_currentPage == 0)

{

// Si esta es la primera página, a continuación, también incluye entonces un conteo de todos los títulos.

queryUri = new Uri(queryUri.ToString() +

"&$inlinecount=allpages", UriKind.Relative);

}

return queryUri;

}

 

En este ejemplo, el tamaño de página es fijo, y el número de entradas a saltar se calcula basándose en el número de página actual.  Cuando se carga la primera página, también incluimos la opción de consulta $inlinecount=allpages para solicitar un conteo total de todas las entidades del título, que se utiliza para calcular el número total de páginas que son mostradas en TitlesPage.xaml.             

Cuando se recibe la respuesta, el cliente dispara el evento LoadCompleted.  Cuando hay páginas adicionales para cargar debido a que es paginación del lado del servidor, la propiedad Continuation de DataServiceCollection devuelve una token de continuación.  El siguiente método maneja el evento LoadCompleted para cargar todas las páginas del lado del servidor:

C#

private void OnTitlesLoaded(object sender, LoadCompletedEventArgs e)

{

if (Titles.Continuation != null)

{

Titles.LoadNextPartialSetAsync();

}

/ / Establecer el número total de páginas, si se solicita uno.

if (e.QueryOperationResponse.Query

.RequestUri.Query.Contains("$inlinecount=allpages"))

{

_totalCount = (int)e.QueryOperationResponse.TotalCount;

}

IsDataLoaded = true;

/ / actualiza PagesLoadedText

NotifyPropertyChanged("PagesLoadedText");

}

 

Nota que también leemos y almacenamos el valor de TotalCount cuando se solicita en la consulta