Windows Phone 7 – Tutorial XXX–Seguridad IV – Seguridad en la red

Si tu aplicación accede a datos sensibles a través de la conexión de datos debemos asegurarnos en implementar mecanismos de autenticación como certificados  y  SSL para la encriptación de datos.

Conexiones Seguras con SSL

El protocolo SSL es el mas sofisticado a la hora de securizar conexiones entre el cliente (nuestro teléfono) y el servicio, utiliza el concepto de criptografia asimétrica y certificación. Cuando Windows Phone inicia una conexión aun servicio remoto se chequea el certificado y la autoridad que emitió el certificado, una vez que el CA es conocido Windows Phone 7 chequea si esta en su lista de entidades certificadoras. Si la encuentra inicia la conexión segura, en caso contario nos mostrará un error y no se conectará al servicio entendiendo que no es de confianza.

Windows Phone 7 viene con algunas entidades certificadoras instaladas, en esta entrada http://msdn.microsoft.com/en-us/library/gg521150(v=VS.92).aspx tenéis la lista completa.

Si queremos testear y abrir una conexión SSL por ejemplo con PayPal vamos a seguir los siguientes pasos.

 

El camino mas rápido para testear una conexión SSL es utilizar el navegador del emulador, abrimos internet explorer en el emulador y ponemos la dirección https://www.paypal.com deberíamos de ver la página de PayPal correctamente

 

image   

 

Vamos a crear una pequeña aplicación para conectarnos a PayPal a través de SSL, lo que nos serviría como ejemplo de conexión a cualquier servicio que sea expuesto a través de SSL siempre que este en la lista de entidades certificadoras que viene en Windows Phone 7 el certificado que utilice.

Creamos la aplicación SSLConnection

 

image

En la pantalla arrastramos un control WebBrowser quedándonos el XAML

 

1 <Grid x:Name="LayoutRoot" Background="Transparent"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="Auto"/> 4 <RowDefinition Height="*"/> 5 </Grid.RowDefinitions> 6 7 <!--TitlePanel contains the name of the application and page title--> 8 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 9 <TextBlock x:Name="SSLConection" Text="SSLConection" Style="{StaticResource PhoneTextNormalStyle}"/> 10 <TextBlock x:Name="PayPal" Text="PayPal" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 11 </StackPanel> 12 13 <!--ContentPanel - place additional content here--> 14 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 15 <phone:WebBrowser HorizontalAlignment="Left" Margin="6,6,0,0" Name="webBrowser1" VerticalAlignment="Top" Height="595" Width="450" /> 16 </Grid> 17 </Grid>

 

Ahora en code-behind en el constructor añadimos el código

 

1 WebClient client = new WebClient(); 2 client.OpenReadCompleted += new 3 OpenReadCompletedEventHandler(HandleResponse); 4 client.OpenReadAsync(new Uri("https://www.paypal.com"));

Y en el manejador del evento

1 void HandleResponse(object sender, OpenReadCompletedEventArgs e) 2 { 3 StreamReader reader = new StreamReader(e.Result); 4 string res = reader.ReadToEnd(); 5 webBrowser1.NavigateToString(res); 6 }

El resultado de ejecutarlas es

 

image

 

Como podéis ver en este tonto ejemplo al ser una entidad certificadora que ya viene instalada en el teléfono no tenemos que hacer nada especial, pero que pasa si quiero usar mi propio certificado ya que utilizar el de estas entidades certificadoras me sale caro, en este caso deberemos de realizar los siguientes pasos

Crear mi propio certificado

Con ISS 7 puedo crear mis propios certificados y además habilitar SSL usando estos certificados de una manera sencilla con estos pasos que explicamos a continuación

 

Abrimos el IIS Manager  Start –> Control Panel –> Administrative Tools –>Internet Information Services (IIS) Manager. Una vez abierto creamos un nuevo sitio Web y le llamamos WP7Server con las propiedades de la imagen

 

image

El siguiente paso es crear nuestro propio certificado, para ello seleccionamos el nodo raíz y nos aparece Certificados del servidor

image

 

Lo seleccionamos y en el menú de la derecha seleccionamos Crear Certificado Autofirmado y le damos el nombre de wp7cert.

 

image

Ahora debemos de habilitar SSL en el sitio web para ello seleccionamos el sitio Web y en el menú de la derecha hacemos click en Enlaces

image

Agregamos uno y en la pantalla seleccionamos https y al pedir el certificado seleccionamos el que hemos creado

image

Ahora necesitamos crear contenido en nuestro sitio web, para este ejemplo crearemos una sencilla pagina html con este código

 

1 <html> 2 <h1>Hola, Windows Phone 7</h1> 3 </html>

Al archivo lo llamaremos index.html, ahora si abrimos internet explorer con la url https://localhost/WP7Server obtendremos la siguiente pantalla

 

image

Si diésemos a continuar accederíamos al sitio web ya que indicamos que confiamos en el certificado, pero esto no es deseable en nuestros desarrollos ya que deberíamos instalar  el certificado en nuestros dispositivos para que no salga la pantalla de advertencia. Para ello seguiremos los siguientes pasos

Primero exportar el certificado para ello desde Internet Explorer pulsamos en Tools y en la pestaña Content pulsamos en certificados

imageimage

Dentro de la lista seleccionamos el que hemos creado y le damos a exportar

image

 

Seleccionamos No exportar la clase privada

image

Seleccionamos DER binario codificado X.509 y el siguiente paso es darle el nombre del fichero, para instalarlo en nuestro dispositivo o emulador lo haremos a través del correo, en el coreo lo seleccionaremos y lo instalaremos de manera que cuando utilicemos este certificado nuestro dispositivo lo reconocerá, para instalarlo en el emulador lo podemos enviar a una cuenta de hotmail y desde el navegador acceder al mensaje.

En el ejemplo hemos visto como acceder a una pagina web nuestra con SSL, este mismo ejemplo de instalación nos valdría para la comunicación entre servicios WCF, por ejemplo si tenemos un servicio con transporte sobre SSL

 

 

1 < system.serviceModel > 2 < services > 3 < service behaviorConfiguration=”SSLServiceBehaviors” 4 name=”WebAuthSample.SSLService” > 5 < endpoint binding=”basicHttpBinding” 6 bindingConfiguration=”securedWithSSL” 7 contract=”WebAuthSample.ISSLService” / > 8 < /service > 9 < /services > 10 < bindings > 11 < basicHttpBinding > 12 <binding name=”securedWithSSL” > 13 <security mode=”Transport” /> 14 </binding> 15 </basicHttpBinding> 16 </bindings> 17 <behaviors> 18 <serviceBehaviors> 19 <behavior name=”SSLServiceBehaviors”> 20 <serviceDebug includeExceptionDetailInFaults=”false” /> 21 </behavior> 22 </serviceBehaviors> 23 </behaviors> 24 </system.serviceModel>

 

 

Las líneas importantes son :

<binding name=”securedWithSSL” >

    <security mode=”Transport” />

</binding>

 

En el cliente, en nuestra aplicación de teléfono

 

1 < system.serviceModel > 2 < bindings > 3 < basicHttpBinding > 4 < binding name=”BasicHttpBinding_ISSLService” maxBufferSize=”2147483647” 5 maxReceivedMessageSize=”2147483647” > 6 <security mode=”Transport” /> 7 </binding> 8 </basicHttpBinding> 9 </bindings> 10 <client> 11 <endpoint address=”https://developmentserver/WebAuthSample/SSLService.svc” 12 binding=”basicHttpBinding” 13 bindingConfiguration=”BasicHttpBinding_ISSLService” 14 contract=”SecuredService.ISSLService” 15 name=”BasicHttpBinding_ISSLService” /> 16 </client> 17 </system.serviceModel>

Con esta configuración podemos invocar un servicio WCF sobre SSL , simplemente indicando el endpoint seguro es decir que la dirección comience por https

Windows Phone 7 – Tutorial XXIX–Seguridad III – Encriptación de Datos II

En el anterior artículo vimos la encriptación HMAC, en este vamos a ver

 

Rfc2898DeriveBytes y AES para Encriptación de Datos

Para cifrar los datos de miradas indiscretas en un dispositivo de Windows 7, se necesita un cifrado de alta seguridad mecanismo que, a su vez, se basa en una clave de cifrado fuerte para soportar todos los intentos de romperla. El algoritmo Rfc2898DeriveBytes crea una clave en encriptación para usarlo en una encriotacion AES como password. En el siguiente ejemplo vamos a ver como utilizar estos dos algoritmos conjuntamente para construir un cifrado muy complicado de romper.

En este caso crearemos una solución con el nombre AESEncryption

image_thumb9

Nuestra interfaz de usuario seria de la siguiente manera

1 <Grid x:Name="LayoutRoot" Background="Transparent"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="Auto"/> 4 <RowDefinition Height="*"/> 5 </Grid.RowDefinitions> 6 <!--TitlePanel contains the name of the application and page title--> 7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12"> 8 <TextBlock x:Name="ApplicationTitle" Text="CLASSIFIED" Style="{StaticResource PhoneTextNormalStyle}"/> 9 <TextBlock x:Name="PageTitle" Text="AES Encryption" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 10 </StackPanel> 11 <!--ContentPanel - place additional content here--> 12 <Grid x:Name="ContentGrid" Grid.Row="1"> 13 <TextBox Height="65" HorizontalAlignment="Left" Margin="6,41,0,0" Name="txtDataToEncrypt" Text="" VerticalAlignment="Top" Width="462" /> 14 <TextBlock Height="30" HorizontalAlignment="Left" Margin="20,21,0,0" Name="textBlock1" Text="Datos a encriptar:" VerticalAlignment="Top" Width="419" /> 15 <TextBox Height="72" HorizontalAlignment="Left" Margin="6,334,0,0" Name="txtPassword" Text="" VerticalAlignment="Top" Width="462" /> 16 <TextBlock Height="30" HorizontalAlignment="Left" Margin="20,310,0,0" Name="textBlock2" Text="Password" VerticalAlignment="Top" Width="346" /> 17 <TextBox Height="72" HorizontalAlignment="Left" Margin="6,426,0,0" Name="txtSalt" Text="" VerticalAlignment="Top" Width="462" /> 18 <TextBlock Height="36" HorizontalAlignment="Left" Margin="21,403,0,0" Name="textBlock3" Text="Salt:" VerticalAlignment="Top" Width="304" /> 19 <Button Content="Encrypt" Height="72" HorizontalAlignment="Left" Margin="20,504,0,0" Name="button1" VerticalAlignment="Top" Width="160" Click="button1_Click" 20 /> 21 <TextBlock Height="30" HorizontalAlignment="Left" Margin="24,101,0,0" Name="textBlock4" Text="Datos encriptados" VerticalAlignment="Top" Width="432" /> 22 <TextBox Height="72" HorizontalAlignment="Left" Margin="8,123,0,0" Name="txtEncryptedData" Text="" VerticalAlignment="Top" Width="460" /> 23 <TextBlock Height="27" HorizontalAlignment="Left" Margin="21,197,0,00" Name="textBlock5" Text="Datos Desencriptados" VerticalAlignment="Top" Width="435" /> 24 <TextBox Height="72" HorizontalAlignment="Left" Margin="13,221,0,0" Name="txtDecryptedData" Text="" VerticalAlignment="Top" Width="460" /> 25 </Grid> 26 </Grid> 27

Lo que nos daría la siguiente pantalla

image_thumb12

Vamos a encriptar el mensaje y desencriptarlo después, para el método de encriptación necesitaremos el mensaje a encriptar, la password y salt que iran como parámetros, utilizaremos la clase Rfc2898DerivedBytes para generar una key a partir de la password y salt, esta key se utilizara en el algoritmo AES para encriptar los datos. El código seria el siguiente

1 public string Encrypt(string dataToEncrypt, string password, string salt) 2 { 3 AesManaged aes = null; 4 MemoryStream memStream = null; 5 CryptoStream crStream = null; 6 try 7 { 8 //Generate a Key based on a Password and Salt 9 Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, 10 Encoding.UTF8.GetBytes(salt)); 11 //Create AES algorithm with 256 bit key and 128-bit block size 12 aes = new AesManaged(); 13 aes.Key = rfc2898.GetBytes(aes.KeySize / 8); 14 aes.IV = rfc2898.GetBytes(aes.BlockSize / 8); 15 memStream = new MemoryStream(); 16 crStream = new CryptoStream(memStream, aes.CreateEncryptor(),CryptoStreamMode.Write); 17 byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt); 18 crStream.Write(data, 0, data.Length); 19 crStream.FlushFinalBlock(); 20 //Return Base 64 String 21 return Convert.ToBase64String(memStream.ToArray()); 22 } 23 finally 24 { 25 //cleanup 26 if (crStream != null) 27 crStream.Close(); 28 if (memStream != null) 29 memStream.Close(); 30 if (aes != null) 31 aes.Clear(); 32 } 33 } 34

Ahora para desenciptarlo el método recibirá como parámetros el mensaje encriptado la password y salt, como AES es un algoritmo simetrico utilizara la password calculada anteriormente para descencriptar el mensaje .

1 public string Decrypt(string dataToDecrypt, string password, string salt) 2 { 3 AesManaged aes = null; 4 MemoryStream memStream = null; 5 CryptoStream crStream = null; 6 try 7 { 8 Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt)); 9 aes = new AesManaged(); 10 aes.Key = rfc2898.GetBytes(aes.KeySize / 8); 11 aes.IV = rfc2898.GetBytes(aes.BlockSize / 8); 12 memStream = new MemoryStream(); 13 crStream = new CryptoStream(memStream, aes.CreateDecryptor(), 14 CryptoStreamMode.Write); 15 byte[] data = Convert.FromBase64String(dataToDecrypt); 16 crStream.Write(data, 0, data.Length); 17 crStream.FlushFinalBlock(); 18 byte[] decryptBytes = memStream.ToArray(); 19 return Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length); 20 } 21 finally 22 { 23 if (crStream != null) 24 crStream.Close(); 25 if (memStream != null) 26 memStream.Close(); 27 if (aes != null) 28 aes.Clear(); 29 } 30 } 31

Ya solo nos queda llamar a los métodos y mostrar los mensajes encriptados y desencriptados en los textbox.

1 private void button1_Click(object sender, RoutedEventArgs e) 2 { 3 txtEncryptedData.Text = Encrypt(txtDataToEncrypt.Text, txtPassword.Text, txtSalt.Text); 4 txtDecryptedData.Text = Decrypt(txtEncryptedData.Text, txtPassword.Text,txtSalt.Text); 5 } 6

Ejecutando la aplicación obtendríamos

image_thumb14

Como habéis podido ver es muy sencillo proteger nuestros datos encriptandolos, lo debemos de recordar cada vez que tratemos datos sensibles para el usuario.

Windows Phone 7 – Tutorial XXVIII–Seguridad II – Encriptación de Datos

En este segundo articulo sobre seguridad en Windows Phone 7 nos vamos a centrar en las posibilidades de encriptación de datos que ofrece Windows Phone 7. Cuando desarrollamos nuestra aplicación y guardamos datos en el teléfono a través de IsolatedStorage debemos de tener en cuenta si esos datos son sensibles como contraseñas, datos personales…, si es así, deberemos de preocuparnos de encriptar esos datos para que en el caso de accesos indebidos estos datos no sean legibles.

Windows Phone 7 nos provee a los desarrolladores de unas clases de encriptación que deberemos utilizar y que nos hace muy fácil la tarea de dotar de seguridad a nuestros desarrollos. Los algoritmos de encriptación que se nos ofrece son:

• AES
• HMACSHA1
• HMACSHA256
• Rfc2898DeriveBytes
• SHA1
• SHA256

AES es un algoritmo de encriptación simétrico, es decir, se usa la misma clave (Password) tanto para encriptar como desencriptar datos.El algoritmo AES utiliza una de las tres fortalezas de clave de cifrado: una clave de encriptación (contraseña) de 128-, 192-, o 256- bits. Cada tamaño de la clave de cifrado hace que el algoritmo se comporte ligeramente diferente, por lo que el aumento de tamaño de clave no sólo ofrecen un mayor número de bits con el que se pueden cifrar los datos, sino también aumentar la complejidad del algoritmo de cifrado.

HMACSHA1 y HMACSHA256 son algoritmos generados por un unico mensaje de autentificación (MAC) a partir de los datos y contraseña proporcionados.

Ambos algoritmos utiliza el mismo enfoque para la generación de la MAC: toman los datos y el hash con la clave secreta usando la función hash SHA1 y SHA256
Rfc2898DeriveBytes es un algoritmo que implementa PBKDF2 (función de derivación de claves basada en contraseña) utilizando un generador de números pseudoaleatorios basado en HMACSHA1 .

Vamos a ver ejemplos de algunas de las funciones de encriptación de datos para ver como se utilizan en nuestros desarrollos.

HMACSHA1 y HMACHSHA256

El primer ejemplo que vamos a construir paso a paso va a ser la implementación de estos algoritmos. Nuestro primer paso es crear una solución en Visual Studio 2010 a la que vamos a llamar HMACTest

 

image

Definiremos nuestra interfaz de usuario de la siguiente manera

1 <Grid x:Name="LayoutRoot" Background="Transparent"> 2 <Grid.RowDefinitions> 3 <RowDefinition Height="Auto"/> 4 <RowDefinition Height="*"/> 5 </Grid.RowDefinitions> 6 <!--TitlePanel contains the name of the application and page title--> 7 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12"> 8 <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> 9 <TextBlock x:Name="PageTitle" Text="HMAC Test" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 10 </StackPanel> 11 <!--ContentPanel - place additional content here--> 12 <Grid x:Name="ContentGrid" Grid.Row="1"> 13 <Button Content="Generate" Height="72" HorizontalAlignment="Left" Margin="149,437,0,0" Name="button1" VerticalAlignment="Top" Width="160" Click="button1_Click"/> 14 <TextBox Height="72" HorizontalAlignment="Left" Margin="149,23,0,0" Name="txtMessage" Text="" VerticalAlignment="Top" Width="317" /> 15 <TextBlock Height="99" HorizontalAlignment="Left" Margin="21,216,0,0" Name="textBlock1" Text="TextBlock" VerticalAlignment="Top" Width="445" TextWrapping="Wrap" /> 16 <TextBlock Height="114" HorizontalAlignment="Left" Margin="24,321,0,0" Name="textBlock2" Text="TextBlock" VerticalAlignment="Top" Width="442" TextWrapping="Wrap" /> 17 18 <TextBlock Height="30" HorizontalAlignment="Left" Margin="21,44,0,0" Name="textBlock3" Text="Mensaje:" VerticalAlignment="Top" Width="122" /> 19 <TextBlock Height="30" HorizontalAlignment="Left" Margin="21,129,0,0" Name="textBlock4" Text="Clave:" VerticalAlignment="Top" /> 20 <TextBox Height="72" HorizontalAlignment="Left" Margin="149,101,0,0" Name="txtKey" Text="" VerticalAlignment="Top" Width="246" /> 21 </Grid> 22 </Grid> 23

Que corresponde con la pantalla

 

image

Ahora vamos a codificar la aplicación para utilizar estos algoritmos de encriptación, el primer paso es añadir el using al assemblie System.Security.Cryptography, una vez añadido ya podemos utilizar los algoritmos que codificaremos en el evento del botón.

1 string message = txtMessage.Text; 2 string key = txtKey.Text; 3 System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 4 byte[] keyByte = encoding.GetBytes(key); 5 HMACSHA1 hmacsha1 = new HMACSHA1(keyByte); 6 HMACSHA256 hmacsha256 = new HMACSHA256(keyByte); 7 byte[] messageBytes = encoding.GetBytes(message); 8 byte[] hashmessage = hmacsha1.ComputeHash(messageBytes); 9 textBlock1.Text = ConvertToString(hashmessage); 10 hashmessage = hmacsha256.ComputeHash(messageBytes); 11 textBlock2.Text = ConvertToString(hashmessage);

Como podéis observar en el código de arriba la magia esta en el método ComputeHash que transforma el mensaje en el array de bytes codificado a partir de la clave introducida, luego utilizamos el método ConvertToString para pasar del array de bytes a un string para mostrarlo en pantalla

1 public static string ConvertToString(byte[] buff) 2 { 3 string sbinary = ""; 4 for (int i = 0; i < buff.Length; i++) 5 { 6 //hex-formatted 7 sbinary += buff[i].ToString("X2"); 8 } 9 return (sbinary); 10 } 11 } 12

Si ejecutamos la aplicación e introducimos los valores Hola Mundo para el mensaje y test para la clave obtendremos

image

 

Podéis observar la longitud de la MAC generada por uno y otro algoritmo, esta longitud es claramente mayor en el algoritmo HMACSHA256.

 

Windows Phone 7 – Tutorial XXVII–Seguridad I – Dispositivo Fisico

Este es el primer articulo de una serie dedicada a la seguridad en el desarrollo de aplicaciones para Windows Phone 7 en Silverlight, en los que iremos tratando los diferentes elementos que tenemos para realizar aplicaciones seguras para Windows Phone7. En este primer articulo veremos la seguridad que nos da el sistema operativo como usuario y como Microsoft se ha tomado en serio la seguridad en este dispositivo.

Como usuario de Windows Phone 7 debemos de proteger nuestros datos tanto para robos como accesos indebidos a nuestro dispositivo, la primera acción que tenemos que realizar es activar la solicitud de password cuando desbloquemos nuestro teléfono para realizar cualquier acción, esto es muy sencillo de realizar y en las siguientes imágenes podéis ver los pasos a realizar.

image

La acción de poner una password de acceso a nuestro teléfono podéis pensar que es básica, pero si además de proteger nuestro teléfono mediante la introducción de una password, se nos ofrece una web desde la que podemos localizar nuestro teléfono, hacerlo sonar, bloquearlo e incluso borrar los datos almacenados en el teléfono, podemos ir muy tranquilos con nuestro dispositivo de windows phone 7 contra robos y perdidas.

En el portal http://windowsphone.live.com asociaremos nuestro teléfono con un id de Windows Live y a partir de entonces tendremos acceso a nuestro dispositivo físico desde la web

image 

Podemos enviarle un mensaje a la vez que lo bloqueamos, este bloqueo no inutiliza el telefono sino que es necesario introducir una password para que el telefono pueda volver a ser usado.

image

También podemos localizarlo en un mapa por si nos hemos olvidado de el en algún lugar y no recordamos, donde, la función “Map it” nos mostrará la situación de nuestro  teléfono en un mapa, esta localización se produce con el GPS que viene incorporado o a través de las antenas GSM o wifi.

image

Como podéis ver la seguridad física que se ofrece en un teléfono Windows Phone 7 es bastante completa y estudiada para proteger nuestro teléfono y datos contra accesos indebidos. En los siguientes artículos veremos el concepto de seguridad desde el punto de vista del desarrollador.

Windows Phone 7 – Tutorial XXVI–Touch Input VI

Durante los anteriores artículos hemos visto como detectar y programar los gestos que realice el usuario en nuestras aplicaciones, pero para hacernos mas facil la vida el equipo de Silverlight lanzo Silverlight for Windows Phone Toolkit en el que nos proporciona una serie de clases que nos permitirán detectar los gestos del usuario de una manera mas sencilla y de programación de alto nivel. Concretamente nos proporcionan los objetos GestureService y GestureListener. En la siguiente figura vemos los gestos que podremos capturar con estos objetos.

Windows Phone 7 Gestures

 

Una vez que tenemos instalado el Toolkit solo tenemos que añadir la referencia al assembly Microsoft.Phone.Controls.Toolkit y referenciarlo en el XAML

1 xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

El siguiente paso es añadir una instancia del objeto GestureListener  al elemento donde queremos capturar los gestos del usuario por ejemplo a un grid

 

1 <Grid x:Name="LayoutRoot" Background="Transparent"> 2 <toolkit:GestureService.GestureListener> 3 <toolkit:GestureListener x:Name="gl" /> 4 </toolkit:GestureService.GestureListener> 5 ;.... 6 </Grid>

Para los gestos simples manejaremos un evento en el GestureListener utilizando los eventos que nos proporciona esta clase, a continuación pongo una lista para detectar los diferentes gestos y que eventos debemos utilizar en cada uno de ellos

  • Tap – EventArgs: (point)Origin, (object)OriginalSource
  • DoubleTap – EventArgs: (point)Origin, (object)OriginalSource
  • Flick – EventArgs: (double)Angle, (Orientation)Direction, (double)HorizontalVelocity, (double)VerticalVelocity

Para el gesto Pan

  • DragStarted –  EventArgs: (Orientation)Direction
  • DragCompleted – EventArgs: (Orientation)Direction, (double) HorizontalVelocity, (double) VerticalVelocity, (double) HorizontalChange, (double) VerticalChange

Para el gesto Pinch Stretch :

  • Tap – captura la coordenada original
  • PinchStarted – EventArgs: (double) Angle, (double) Distance – entre los dos puntos
  • PinchDelta –   EventArgs: (double) DistanceRatio, (double) TotalAngleDelta
  • PinchCompleted – EventArgs: (double) DistanceRatio, (double) TotalAngleDelta

Para Touch & Hold :

  • Tap
  • Hold – EventArgs: (point)Origin

Por ejemplo para hacer el gesto pinch en una imagen suscribimos el servicio GestureListener a la imagen

 

1 <Image x:Name="MyImage" 2 Source="Phone.png"> 3 <Image.RenderTransform> 4 <CompositeTransform x:Name="ImageTransformation" /> 5 </Image.RenderTransform> 6 <toolkit:GestureService.GestureListener> 7 <toolkit:GestureListener PinchStarted="OnPinchStarted" 8 PinchDelta="OnPinchDelta" /> 9 </toolkit:GestureService.GestureListener> 10 </Image>

En los eventos deberíamos de detectar los dos dedos y realizar las transformaciones necesarias en la imagen

 

1 private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e) 2 { 3 // store the initial rotation angle and scaling 4 _initialAngle = ImageTransformation.Rotation; 5 _initialScale = ImageTransformation.ScaleX; 6 7 // calculate the center for the zooming 8 Point firstTouch = e.GetPosition(MyImage, 0); 9 Point secondTouch = e.GetPosition(MyImage, 1); 10 11 Point center = new Point(firstTouch.X + (secondTouch.X - firstTouch.X) / 2.0, 12 firstTouch.Y + (secondTouch.Y - firstTouch.Y) / 2.0); 13 14 ImageTransformation.CenterX = center.X; 15 ImageTransformation.CenterY = center.Y; 16 }

Cuando el usuario pone los dedos en la pantalla y los gira recibiremos el evento PinchDelta y realizaremos las transformaciones en la imagen

 

1 private void OnPinchDelta(object sender, PinchGestureEventArgs e) 2 { 3 // update the rotation and scaling 4 ImageTransformation.Rotation = _initialAngle + e.TotalAngleDelta; 5 ImageTransformation.ScaleX = _initialScale * e.DistanceRatio; 6 ImageTransformation.ScaleY = ImageTransformation.ScaleX; 7 }

Como veis es mas sencillo de utilizar que meternos a bajo nivel como en los anteriores artículos, podéis ver mejor su utilización Silverlight for Windows Phone Toolkit

Windows Phone 7 – Tutorial XXV–Touch Input V

En esta entrada trataremos el MultiTouch, Windows Phone 7 exige a todos los fabricantes que la pantalla que implemente soporte MultiTouch, con lo que deberemos ver si nuestras aplicaciones necesitan reconocer gestos Multitouch como Pinch And Strech. Si tienes un teléfono te será fácil desarrollar en multitouch, pero si no lo tienes deberas realizar tu desarrollo a través del emulador. Si tienes Windows 7 y eres el afortunado de poseer un ordenador que posee Multitouch no tendrás que realizar nada para poder desarrollar pero si no lo eres tendremos que simularlo a través de varios ratones usb, para ello utilizaremos el proyecto http://multitouchvista.codeplex.com/ que inicialmente fue desarrollado para simular Multitouch en windows Vista, conn la llegada de Windows 7, que incluye una multitouch ,este proyecto se limita a establecer el enlace entre varios ratones USB y la función nativa de Windows 7 para el multitouch. De esta manera podremos utilizar nuestro emulador con dos ratones a la vez. Los pasos que necesitamos para instalarlo son:

  1. Bajarnos el proyecto http://multitouchvista.codeplex.com/
  2. Descomprimir el fichero
  3. Navegar hasta la carpeta Drivers x86 o x64 dependiendo de tu procesador
  4. Ejecutar en modo administrador el archivo drive.cmd
  5. Confirma todos los mensajes que te muestre al realizar la instalación, incluso el que te muestra que Windows no puede verificar el
  6. Cuando esten todos los pasos completos cierra el Command Prompt
  7. Abre Device Manager (Start ➪ Right – click Computer ➪ Properties ➪ Device Manager).
  8. Busca Universal Software HID que debe de aparecer bajo  Human Interface Devices node, pulsa el botón derecho del ratón y deshabilítalo
  9. Vuelve a pulsar el botón derecho del ratón y esta vez habilítalo pulsando en Enable, esto puede parecer un poco tonto pero a veces si no se hacen estos pasos el driver no funciona
  10. Abre Pen and Touch settings (Start ➪ Control Panel ➪ Pen and Touch), pulsa la pestaña Touch y selecciona “Show the touch pointer when I ’ m
    interacting with items on the screen”
  11. Abre Windows Explorer y ve a la carpeta donde has extraido el Zip en el paso 2 y ejecuta Multitouch.Service.Console.exe de esta manera arrancaras el servicio de Multitouch, deberian de aparecer uno o mas puntos rojos, uno por cada ratón usb que tengas puesto, pero no se moverán hasta que hagas el siguiente paso
  12. Ejecuta Multitouch.Driver.Console.exe para empezar el multitouch driver
  13. Ejecuta Multitouch.Confi guration.WPF.exe para configurar la herramienta Multitouch Vista

image

Ya tenemos habilitado nuestro simulador de Multitouch lo podemos probar abriendo Päint y con los dos ratones dibujando en el.

Pinch And Strecht

 

clip_image006

Este gesto es el típico utilizado para realizar Zoom in y Zoom out, vamos a implementar el behaivor en la aplicación que estamos utilizando para ver este efecto

 

image 

Al behaivor le vamos a llamar ZoomAction y heredará del ultimo que hemos creado FlickAction. Cuando varios puntos son utilizados el evento ManipulationDelta es lanzado varias veces,  Los datos suministrados  de este evento nos da una indicación de si los puntos de se mueven una hacia la otra (pin) o fuera de ella
(strecht)

 

1 public class ZoomAction : FlickAction 2 { 3 private bool DisablePan; 4 5 protected override void OnAttached() 6 { 7 base.OnAttached(); 8 9 this.AssociatedObject.ManipulationDelta += AO_ManipulationDelta; 10 this.AssociatedObject.ManipulationCompleted += AO_ManipulationCompleted; 11 } 12 13 protected override void OnDetaching() 14 { 15 this.AssociatedObject.ManipulationDelta -= AO_ManipulationDelta; 16 this.AssociatedObject.ManipulationCompleted -= AO_ManipulationCompleted; 17 18 base.OnDetaching(); 19 } 20 21 protected override void AO_MouseMove(object sender, MouseEventArgs e) 22 { 23 if (DisablePan) 24 { 25 return; 26 } 27 base.AO_MouseMove(sender, e); 28 } 29 30 void AO_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e) 31 { 32 DisablePan = false; 33 } 34 35 void AO_ManipulationDelta(object sender, ManipulationDeltaEventArgs e) 36 { 37 if (e.CumulativeManipulation.Scale.X > 0 || 38 e.CumulativeManipulation.Scale.Y > 0) 39 { 40 DisablePan = true; 41 42 var scaleX = e.DeltaManipulation.Scale.X; 43 var scaleY = e.DeltaManipulation.Scale.Y; 44 foreach (var child in this.AssociatedObject.Children) 45 { 46 if (scaleX != 0) 47 { 48 var left = Canvas.GetLeft(child); 49 if (left > this.AssociatedObject.ActualWidth / 2) 50 { 51 left *= scaleX; 52 } 53 else 54 { 55 left /= scaleX; 56 } 57 left = Math.Min(Math.Max(0, left), 58 this.AssociatedObject.ActualWidth); 59 Canvas.SetLeft(child, left); 60 } 61 if (scaleY != 0) 62 { 63 var top = Canvas.GetTop(child); 64 if (top > this.AssociatedObject.ActualHeight / 2) 65 { 66 top *= scaleY; 67 } 68 else 69 { 70 top /= scaleY; 71 } 72 top = Math.Min( 73 Math.Max(0, top), this.AssociatedObject.ActualHeight); 74 Canvas.SetTop(child, top); 75 } 76 } 77 } 78 } 79 }

Ahora solo debemos de añadir este behaivor a los objetos en el xaml

1 <i:Interaction.Behaviors> 2 <!--<local:PanAction />--> 3 <!--<local:FlickAction />--> 4 <local:ZoomAction /> 5 </i:Interaction.Behaviors>

A lo largo de los anteriores artículos hemos visto como detectar los gestos y programarlos nosotros mismos, pero en el siguiente veremos como utilizar el toolkit de Silverlight que viene preparado para abstraernos de todo este desarrollo a lahor de implementar gestos en nuestros desarrollos

 

Windows Phone 7 – Tutorial XXIV–Touch Input IV

clip_image003

En los anteriores artículos hemos visto los gestos Tap, DoubleTap, Pan y Flick, en este nos vamos a centrar en Touch and Hold, cuando realizamos aplicaciones para Escritorio solemos utilizar el botón derecho del ratón para sacar generalmente un menú contextual, en los dispositivos tactiles al no tener ratón este evento se simula al pulsar en un lugar durante un determinado tiempo, siguiendo los ejemplos anteriores vamos a construir un behaivor que simule este gesto, lo vamso a llamar TouchAndHoldAction que podremos aplicar a cualquier UIElement.

1 public class TouchAndHoldAction : DoubleTapAction 2 { 3 public event EventHandler TouchAndHold; 4 5 private Point? TapLocation; 6 private DispatcherTimer timer = new DispatcherTimer(); 7 8 public int HoldTimeoutInMilliseconds 9 { 10 get { return (int)GetValue(HoldTimeoutInMillisecondsProperty); } 11 set { SetValue(HoldTimeoutInMillisecondsProperty, value); } 12 } 13 14 public static readonly DependencyProperty HoldTimeoutInMillisecondsProperty = 15 DependencyProperty.Register("HoldTimeoutInMilliseconds", 16 typeof(int), typeof(TouchAndHoldAction), 17 new PropertyMetadata(2000)); 18 19 public int Tolerance 20 { 21 get { return (int)GetValue(ToleranceProperty); } 22 set { SetValue(ToleranceProperty, value); } 23 } 24 25 public static readonly DependencyProperty ToleranceProperty = 26 DependencyProperty.Register("Tolerance", typeof(int), 27 typeof(TouchAndHoldAction), 28 new PropertyMetadata(2)); 29 30 protected override void OnAttached() 31 { 32 base.OnAttached(); 33 34 this.AssociatedObject.MouseLeftButtonDown += AO_MouseLeftButtonDown; 35 this.AssociatedObject.MouseMove += AO_MouseMove; 36 this.timer.Tick += timer_Tick; 37 } 38 39 protected override void OnDetaching() 40 { 41 this.AssociatedObject.MouseLeftButtonDown -= AO_MouseLeftButtonDown; 42 this.AssociatedObject.MouseMove -= AO_MouseMove; 43 this.timer.Tick -= timer_Tick; 44 45 base.OnDetaching(); 46 } 47 48 void AO_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 49 { 50 var pos = e.GetPosition(null); 51 OnTouchAndHoldStarted(pos); 52 } 53 54 void AO_MouseMove(object sender, MouseEventArgs e) 55 { 56 if (TapLocation.HasValue) 57 { 58 var pos = e.GetPosition(null); 59 if (Math.Abs(TapLocation.Value.X - pos.X) > Tolerance || 60 Math.Abs(TapLocation.Value.Y - pos.Y) > Tolerance) 61 { 62 OnTouchAndHoldStarted(pos); 63 } 64 } 65 } 66 67 void timer_Tick(object sender, EventArgs e) 68 { 69 OnTouchAndHoldCompleted(); 70 timer.Stop(); 71 TapLocation = null; 72 } 73 74 protected override void OnTap() 75 { 76 timer.Stop(); 77 base.OnTap(); 78 } 79 80 protected virtual void OnTouchAndHoldStarted(Point pt) 81 { 82 TapLocation = pt; 83 84 timer.Stop(); 85 timer.Interval = new TimeSpan(0, 0, 0, 0, HoldTimeoutInMilliseconds); 86 timer.Start(); 87 } 88 protected virtual void OnTouchAndHoldCompleted() 89 { 90 MouseDown = false; 91 if (TouchAndHold != null) 92 { 93 TouchAndHold(this.AssociatedObject, EventArgs.Empty); 94 } 95 } 96 }

Este behaivor tiene la propiedad HoldTimeoutInMilliseconds que le indicaremos el tiempo en milisegundos que el usuario tiene que tener presionado, si pasa este tiempo lanzara el evento TouchAndHold, luego he puesto la propiedad Tolerance que permitirá al usuario poder desplazar el dedo durante los pixels que le indiquemos en esta propiedad si mueve el demo mas de esta longitud anularemos el vento.

Para el ejemplo vamos a utilizar el código del anterior artículo y pondremos este gesto en todos los borders redondeados que teníamos, el XAML sería

1 <Border HorizontalAlignment="Left" Height="368" Margin="19,231,0,0" VerticalAlignment="Top" Width="441" BorderBrush="White" BorderThickness="2" Background="#FF313131"> 2 <Canvas Background="Transparent"> 3 <Canvas.Resources> 4 <Style x:Key="RoundedBorder" TargetType="Border"> 5 <Setter Property="BorderThickness" Value="3"/> 6 <Setter Property="CornerRadius" Value="20"/> 7 <Setter Property="Background" Value="#FF287E3D"/> 8 <Setter Property="BorderBrush" Value="#FF0F451C"/> 9 <Setter Property="Width" Value="25"/> 10 <Setter Property="Height" Value="25"/> 11 </Style> 12 </Canvas.Resources> 13 <i:Interaction.Behaviors> 14 <!--<local:PanAction />--> 15 <!--<local:FlickAction />--> 16 <!--<local:ZoomAction />--> 17 </i:Interaction.Behaviors> 18 <Border Canvas.Left="43" Canvas.Top="137" Style="{StaticResource RoundedBorder}" > 19 <i:Interaction.Behaviors> 20 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 21 </i:Interaction.Behaviors> 22 </Border> 23 <Border Canvas.Left="122" Canvas.Top="83" Style="{StaticResource RoundedBorder}" > 24 <i:Interaction.Behaviors> 25 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 26 </i:Interaction.Behaviors> 27 </Border> 28 <Border Canvas.Left="294" Canvas.Top="301" Style="{StaticResource RoundedBorder}" > 29 <i:Interaction.Behaviors> 30 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 31 </i:Interaction.Behaviors> 32 </Border> 33 <Border Canvas.Left="273" Canvas.Top="51" Style="{StaticResource RoundedBorder}" > 34 <i:Interaction.Behaviors> 35 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 36 </i:Interaction.Behaviors> 37 </Border> 38 <Border Canvas.Left="74" Canvas.Top="242" Style="{StaticResource RoundedBorder}" > 39 <i:Interaction.Behaviors> 40 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 41 </i:Interaction.Behaviors> 42 </Border> 43 <Border Canvas.Left="236" Canvas.Top="167" Style="{StaticResource RoundedBorder}" > 44 <i:Interaction.Behaviors> 45 <local:TouchAndHoldAction TouchAndHold="TouchAndHoldAction_TouchAndHold" /> 46 </i:Interaction.Behaviors> 47 </Border> 48 </Canvas> 49 </Border>

 

Como podéis ver en el XAML enlazamos el behaivor y lo enlazamos al evento TouchAndHoldAction_TouchAndHold en este evento cambiaremos el colñor de los puntos, quedándonos

image

 

MyNikeplus – Mi primera Aplicación en el Marketplace de Windows Phone 7

Toda la gente que me conoce sabe que correr es una de mis aficiones preferidas y aunque ahora no puedo hacerlo tan habitualmente (la edad, trabajo, niño…), no sigo planes de entrenamiento, ni me planteo objetivos.. sigo saliendo a correr en cuento tengo oportunidad. Como soy poseedor de hace tiempo de Nikeplus aunque no lo utilizo ahora mismo, pensé que mi primera aplicación para Windows Phone 7 podría ser una aplicación que me mostrase todos los datos registrados en Nikeplus en el móvil de Windows Phone 7. Así que me plantee ir aprendiendo los conceptos de Windows Phone 7 e ir publicando artículos mientras iba haciendo la aplicación, además he intentado registrar todo el tiempo consumido (horas libres a retazos) para ver la productividad del entorno y una vez hecha las cuentas mi impresión es que es un entorno realmente productivo.

La aplicación no es excesivamente grande ni compleja, lo mas complejo ha sido localizar si Nikeplus exponía su API y obtener los datos de su API, por desgracia Nikeplus no tiene ninguna documentación y ha sido los mas complejo del proyecto junto con la tarea de certificarme como desarrollador. En total he consumido 92 horas mas o menos, si hacemos cálculos 11 días y medio de una jornada laboral de 8 horas que si se hubiera desarrollado así seguro que habrían sido menos horas, me quedo con la conclusión que podemos realizar aplicaciones para Windows Phone 7 sin invertir mucho esfuerzo.

 

La aplicación se llama MyNikePlus y os dejo un video (pequeñito) de un minuto y poco para que echéis un vistazo a la aplicación

 

Windows Phone 7 – Tutorial XXIII–Touch Input III

En el anterior articulo vimos los dos primeros gestos Tap y Double-Tap, en este vamos a profundizar en los gestos  Pan y Flick.

Pan

clip_image004

 

Este gesto es totalmente diferente a los vistos anteriores el usuario mueve el dedo a través de la pantalla, es como cuando hemos realizado Drag & Drop en aplicaciones de PC, como si el dedo fuese el ratón y controlásemos el evento  MouseMove. Siguiendo la idea que hemos realizado con los dos anteriores gestos vamos a realizar un behaivor al que denominaremos PanAction que nos permita obtener este gesto del usuario y sea redirigido a un evento, la única diferencia con los anteriores es que lo delimitaremos al objeto Canvas  y moveremos todos los hijos del canvas en la dirección que mueva el dedo el usuario, en definitiva implementaremos un Drag&Drop donde el usuario podrá simular los movimientos que vemos en los siguientes dibujos

image

El código correspondiente a este behaivor sería el siguiente

 

1 public class PanAction : Behavior<Canvas> 2 { 3 protected Point? MouseDown; 4 protected UIElement SelectedItem { get; set; } 5 6 protected override void OnAttached() 7 { 8 base.OnAttached(); 9 10 this.AssociatedObject.MouseLeftButtonDown += AO_MouseLeftButtonDown; 11 this.AssociatedObject.MouseLeftButtonUp += AO_MouseLeftButtonUp; 12 this.AssociatedObject.MouseMove += AO_MouseMove; 13 } 14 15 protected override void OnDetaching() 16 { 17 this.AssociatedObject.MouseLeftButtonDown -= AO_MouseLeftButtonDown; 18 this.AssociatedObject.MouseLeftButtonUp -= AO_MouseLeftButtonUp; 19 this.AssociatedObject.MouseMove -= AO_MouseMove; 20 21 base.OnDetaching(); 22 } 23 24 private void AO_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 25 { 26 this.MouseDown = e.GetPosition(null); 27 this.SelectedItem = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), this.AssociatedObject).FirstOrDefault(); 28 if (this.SelectedItem == this.AssociatedObject) 29 { 30 this.SelectedItem = null; 31 } 32 } 33 34 protected virtual void AO_MouseMove(object sender, MouseEventArgs e) 35 { 36 var pos = e.GetPosition(null); 37 var xdiff = pos.X - MouseDown.Value.X; 38 var ydiff = pos.Y - MouseDown.Value.Y; 39 if (MouseDown.HasValue) 40 { 41 MoveSelectedItems(xdiff, ydiff); 42 } 43 MouseDown = pos; 44 } 45 46 private void AO_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 47 { 48 this.SelectedItem = null; 49 this.MouseDown = null; 50 } 51 52 protected void MoveSelectedItems(double xdiff, double ydiff) 53 { 54 if (this.SelectedItem != null) 55 { 56 MoveItem(this.SelectedItem, xdiff, ydiff); 57 } 58 else 59 { 60 foreach (var child in this.AssociatedObject.Children) 61 { 62 MoveItem(child, xdiff, ydiff); 63 } 64 } 65 } 66 67 private void MoveItem(UIElement item, double xdiff, double ydiff) 68 { 69 var left = Canvas.GetLeft(item) + xdiff; 70 left = Math.Min(Math.Max(0, left), this.AssociatedObject.ActualWidth); 71 var top = Canvas.GetTop(item) + ydiff; 72 top = Math.Min(Math.Max(0, top), this.AssociatedObject.ActualHeight); 73 Canvas.SetLeft(item, left); 74 Canvas.SetTop(item, top); 75 } 76 }

Como podeis observar en el código hemos asociado el behaivor a los objetos Canvas y a la hora de”Atacharlo” nos subscribimos a los eventos MouseLeftButtonDown, MouseLeftButtonUp, MouseMove con estos tres eventos tenemos todo lo necesario para simular el Drag&Drop, lo importante esta en el evento MouseLeftButtonDown donde obtenemos los objetos hijos del Canvas a través del método

1 this.SelectedItem = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), this.AssociatedObject).FirstOrDefault();


Una vez recogidos los objetos que el usuario ha “tocado” en el evento MouseMove solo deberemos moverlos. Para probar este behaivor vamos a extender el proyecto anterior para tener un Canvas con puntos verdes que se podrán mover con este behaivor.

 

1 <Border HorizontalAlignment="Left" Height="368" Margin="19,231,0,0" VerticalAlignment="Top" Width="441" BorderBrush="White" BorderThickness="2" Background="#FF313131"> 2 <Canvas Background="Transparent"> 3 <Canvas.Resources> 4 <Style x:Key="RoundedBorder" TargetType="Border"> 5 <Setter Property="BorderThickness" Value="3"/> 6 <Setter Property="CornerRadius" Value="20"/> 7 <Setter Property="Background" Value="#FF287E3D"/> 8 <Setter Property="BorderBrush" Value="#FF0F451C"/> 9 <Setter Property="Width" Value="25"/> 10 <Setter Property="Height" Value="25"/> 11 </Style> 12 </Canvas.Resources> 13 <i:Interaction.Behaviors> 14 <local:PanAction /> 15 16 </i:Interaction.Behaviors> 17 <Border Canvas.Left="43" Canvas.Top="137" Style="{StaticResource RoundedBorder}" > 18 </Border> 19 <Border Canvas.Left="122" Canvas.Top="83" Style="{StaticResource RoundedBorder}" > 20 </Border> 21 <Border Canvas.Left="294" Canvas.Top="301" Style="{StaticResource RoundedBorder}" > 22 </Border> 23 <Border Canvas.Left="273" Canvas.Top="51" Style="{StaticResource RoundedBorder}" > 24 </Border> 25 <Border Canvas.Left="74" Canvas.Top="242" Style="{StaticResource RoundedBorder}" > 26 </Border> 27 <Border Canvas.Left="236" Canvas.Top="167" Style="{StaticResource RoundedBorder}" > 28 </Border> 29 </Canvas> 30 </Border>

 

Obtendríamos la siguiente pantalla

 

image

 

Flick

clip_image005

 

Conceptualmente hay dos tipos de Flick uno empieza cuando el usuario toca la pantalla y el otro ocurre al final de un Pan, sin embargo si trsladamos esto a código podemos pensar que ambos ocurren al final de un pan, para el primero es un pan con distancia cero, por esta razón voy a construir el behaivor para el gesto Flick a partir del behaivor Pan.

Le vamos a denominar FlickAction y para detectar esta acción deberemos saber la velocidad con la que el dedo del usuario estaba moviéndose en el momento que soltó el dedo de la pantalla.  Los eventos de Mouse que hemos ido utilizando no nos sirven ya que no nos ofrecen este detalle. Windows Phone expone otros eventos diferentes a los que tiene Silverlight 3, estos eventos nos proporciona información asociada a los gestos del usuario ManipulationStarted , ManipulationDelta , y ManipulationCompleted . ManipulationStarted es lanzado cuando comienza un evento de “manipulación”, es decir, el usuario toca la pantalla en uno o mas puntos, cuando el usuario cambia de posición el dedo se lanza el evento ManipulationDelta, por último cuando se suelta uno o mas dedos de la pantalla se lanza el evento  ManipulationCompleted 

Para nuestro behaivor deberemos de implementar el evento ManipulationCompleted porque expone la propiedad FinalVelocities que nos indica la velocidad (en unidades de pantalla por segundo) que el usuario soltó el dedo de la pantalla. Para este behaivor vamos a simular un drift effect muy sencillo sin implementar fisica.

Este behaivor expondrá la propiedad FlickDurationInMilliseconds que sera la cantidad de tiempo que el control continuara moviéndose despues de que el usuario suelte el dedo.

 

1 public class FlickAction : PanAction 2 { 3 private const int Increments = 10; 4 private const double Deceleration = 0.4; 5 6 DispatcherTimer timer = new DispatcherTimer(); 7 8 public int Counter { get; set; } 9 10 private Point ReleaseVelocity { get; set; } 11 12 public int FlickDurationInMilliseconds 13 { 14 get { return (int)GetValue(FlickDurationInMillisecondsProperty); } 15 set { SetValue(FlickDurationInMillisecondsProperty, value); } 16 } 17 18 public static readonly DependencyProperty FlickDurationInMillisecondsProperty = 19 DependencyProperty.Register("FlickDurationInMilliseconds", 20 typeof(int), typeof(FlickAction), 21 new PropertyMetadata(500)); 22 23 public FlickAction() 24 { 25 timer.Tick += new EventHandler(timer_Tick); 26 } 27 28 protected override void OnAttached() 29 { 30 base.OnAttached(); 31 this.AssociatedObject.ManipulationStarted += AO_ManipulationStarted; 32 this.AssociatedObject.ManipulationCompleted += AO_ManipulationCompleted; 33 } 34 35 protected override void OnDetaching() 36 { 37 this.AssociatedObject.ManipulationStarted -= AO_ManipulationStarted; 38 this.AssociatedObject.ManipulationCompleted -= AO_ManipulationCompleted; 39 base.OnDetaching(); 40 } 41 42 void timer_Tick(object sender, EventArgs e) 43 { 44 Counter--; 45 if (Counter == 0) 46 { 47 timer.Stop(); 48 } 49 50 MoveSelectedItems(ReleaseVelocity.X / 100, ReleaseVelocity.Y / 100); 51 52 ReleaseVelocity = new Point(ReleaseVelocity.X * Deceleration, 53 ReleaseVelocity.Y * Deceleration); 54 } 55 56 void AO_ManipulationStarted(object sender, ManipulationStartedEventArgs e) 57 { 58 timer.Stop(); 59 } 60 61 void AO_ManipulationCompleted(object sender, 62 ManipulationCompletedEventArgs e) 63 { 64 ReleaseVelocity = e.FinalVelocities.LinearVelocity; 65 timer.Interval = new TimeSpan(0, 0, 0, 0, 66 FlickDurationInMilliseconds / Increments); 67 Counter = Increments; 68 timer.Start(); 69 } 70 }

El XAML en este caso es el mismo que el anterior solo que cambiamos el behaivor PanAction por FlickAction

Windows Phone 7 – Tutorial XXII–Touch Input II

Después de dos semanas sin escribir nada debido a que hemos estado a tope con el trabajo, vamos a ver en este post parte de los eventos que vimos en el articulo anterior.

Tap

clip_image001

Este evento funciona como si tuviésemos un ratón en nuestro dedo y reacciona al simple toque de nuestro dedo en la pantalla, como supondréis este gesto viene implementado en muchos controles, por ejemplo el control Button lo expone a través del evento Click 

< Button Content=”Simple Gestures” Name=”SimpleGestureButton” Click=”SimpleGestureButton_Click” / >

Sin embargo no todos los controles exponen el gesto Tap, por ejemplo el elemento Border que hereda de Panel no expone el evento Click, si seguimos el árbol de herencia veremos que llegaremos al elemento UIElement el cual expone los eventos MouseLeftButtonDown y MouseLeftButtonUp . Para simular el gesto de Tap con estos dos eventos podríamos utilizar un behaivor que nos permita reusarlo para cualquier elemento.

Para realizar un behaivor podéis ver este articulo que aunque sea de WPF es lo mismo tanto para Silverlight como WPF, recordar que para realizar un behaivor debemos de añadir la referencia al assemblie System.Windows.Interactivity.dll, el behaivor lo enlazaremos a cualquier elemento de la clase UIElement y lo que hará será lanzar un evento Tap jugando con los dos eventos anteriores, aquí tenéis  el código.

1 public class TapAction : Behavior<UIElement> 2 { 3 public event EventHandler Tap; 4 5 protected bool MouseDown { get; set; } 6 7 protected override void OnAttached() 8 { 9 base.OnAttached(); 10 11 this.AssociatedObject.MouseLeftButtonDown += AO_MouseLeftButtonDown; 12 this.AssociatedObject.MouseLeftButtonUp += AO_MouseLeftButtonUp; 13 } 14 15 protected override void OnDetaching() 16 { 17 this.AssociatedObject.MouseLeftButtonDown -= AO_MouseLeftButtonDown; 18 this.AssociatedObject.MouseLeftButtonUp -= AO_MouseLeftButtonUp; 19 20 base.OnDetaching(); 21 } 22 23 void AO_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 24 { 25 if (MouseDown) 26 { 27 OnTap(); 28 } 29 MouseDown = false; 30 } 31 32 void AO_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 33 { 34 MouseDown = true; 35 } 36 37 protected virtual void OnTap() 38 { 39 if (Tap != null) 40 { 41 Tap(this.AssociatedObject, EventArgs.Empty); 42 } 43 } 44 }

Luego en cualquier elemento como un Border se lo asociaremos por XAML

 

1 <phone:PhoneApplicationPage 2 x:Class="TouchInput.MainPage" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 6 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 7 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 8 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 9 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 10 xmlns:local="clr-namespace:TouchInput.Helper" 11 mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 12 FontFamily="{StaticResource PhoneFontFamilyNormal}" 13 FontSize="{StaticResource PhoneFontSizeNormal}" 14 Foreground="{StaticResource PhoneForegroundBrush}" 15 SupportedOrientations="Portrait" Orientation="Portrait" 16 shell:SystemTray.IsVisible="True"> 17 18 <!--LayoutRoot is the root grid where all page content is placed--> 19 <Grid x:Name="LayoutRoot" Background="Transparent"> 20 <Grid.RowDefinitions> 21 <RowDefinition Height="Auto"/> 22 <RowDefinition Height="*"/> 23 </Grid.RowDefinitions> 24 25 <!--TitlePanel contains the name of the application and page title--> 26 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12"> 27 <TextBlock x:Name="ApplicationTitle" Text="BUILT TO ROAM" Style="{StaticResource PhoneTextNormalStyle}"/> 28 <TextBlock x:Name="PageTitle" Text="flick tap pane" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 29 </StackPanel> 30 31 <!--ContentPanel - place additional content here--> 32 <Grid x:Name="ContentGrid" Grid.Row="1"> 33 <Border BorderBrush="#FFF11717" BorderThickness="2" Height="90" Margin="20,0,0,409" VerticalAlignment="Bottom" Background="#FFCC8787" HorizontalAlignment="Left" Width="160"> 34 <i:Interaction.Behaviors> 35 <local:TapAction Tap="TapGesture_Tap"/> 36 </i:Interaction.Behaviors> 37 </Border> 38 39 </Grid> 40 </Grid>

Para asociar el behaivor por Blend os dejo los siguientes pantallazos:

 

imageimageimage

 

Como podéis ver capturamos el evento Tap y en el code-behind

1 private void TapGesture_Tap(object sender, EventArgs e) 2 { 3 MessageBox.Show("Has hecho TAP en el Border!"); 4 }

De esta manera capturamos todos los eventos de Tap de una manera muy sencilla

 

Double Tap

clip_image002

 

Recordamos que el Double-Tap son dos gestos Tap en un periodo de tiempo muy corto, no existe este evento en ningún objeto con lo que aprovecharemos el behaivor anterior para extenderlo para detectar estos dos Tap, incluiremos una propiedad donde indicaremos el tiempo que queremos que pase entre gesto y gesto, a este behaivor le llamaremos DoubleTapAction, os dejo el código a continuación.

1 public class DoubleTapAction : TapAction 2 { 3 public event EventHandler DoubleTap; 4 5 public int DoubleTapTimeoutInMilliseconds 6 { 7 get { return (int)GetValue(DoubleTapTimeoutInMillisecondsProperty); } 8 set { SetValue(DoubleTapTimeoutInMillisecondsProperty, value); } 9 } 10 11 public static readonly DependencyProperty DoubleTapTimeoutInMillisecondsProperty = 12 DependencyProperty.Register("DoubleTapTimeoutInMilliseconds", typeof(int), 13 typeof(DoubleTapAction), new PropertyMetadata(1000)); 14 15 protected DateTime? FirstTap { get; set; } 16 17 protected override void OnTap() 18 { 19 base.OnTap(); 20 21 if (FirstTap.HasValue && 22 FirstTap.Value.AddMilliseconds(DoubleTapTimeoutInMilliseconds) > DateTime.Now) 23 { 24 OnDoubleTap(); 25 FirstTap = null; 26 } 27 else 28 { 29 FirstTap = DateTime.Now; 30 } 31 } 32 33 protected virtual void OnDoubleTap() 34 { 35 if (DoubleTap != null) 36 { 37 DoubleTap(this.AssociatedObject, EventArgs.Empty); 38 } 39 } 40 }

En el código anterior podéis ver que se ha definido la propiedad DoubleTapTimeoutInMilliseconds  que nos indicará el tiempo entre gestos Tap y se ha definido por defecto que sea de 1 segundo.

1 public class TapAction : Behavior<UIElement> 2 { 3 public event EventHandler Tap; 4 5 protected bool MouseDown { get; set; } 6 7 protected override void OnAttached() 8 { 9 base.OnAttached(); 10 11 this.AssociatedObject.MouseLeftButtonDown += AO_MouseLeftButtonDown; 12 this.AssociatedObject.MouseLeftButtonUp += AO_MouseLeftButtonUp; 13 } 14 15 protected override void OnDetaching() 16 { 17 this.AssociatedObject.MouseLeftButtonDown -= AO_MouseLeftButtonDown; 18 this.AssociatedObject.MouseLeftButtonUp -= AO_MouseLeftButtonUp; 19 20 base.OnDetaching(); 21 } 22 23 void AO_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 24 { 25 if (MouseDown) 26 { 27 OnTap(); 28 } 29 MouseDown = false; 30 } 31 32 void AO_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 33 { 34 MouseDown = true; 35 } 36 37 protected virtual void OnTap() 38 { 39 if (Tap != null) 40 { 41 Tap(this.AssociatedObject, EventArgs.Empty); 42 } 43 } 44 }

El XAML del nuevo Border sería

 

1 <Border BorderBrush="#FFF11717" BorderThickness="2" Margin="0,118,21,0" Background="#FFCC8787" HorizontalAlignment="Right" Width="160" Height="90" VerticalAlignment="Top"> 2 <i:Interaction.Behaviors> 3 <local:DoubleTapAction DoubleTap="DoubleTapGesture_DoubleTap"/> 4 </i:Interaction.Behaviors> 5 </Border>

1 <Border BorderBrush="#FFF11717" BorderThickness="2" Margin="0,118,21,0" Background="#FFCC8787" HorizontalAlignment="Right" Width="160" Height="90" VerticalAlignment="Top"> 2 <i:Interaction.Behaviors> 3 <local:DoubleTapAction DoubleTap="DoubleTapGesture_DoubleTap"/> 4 </i:Interaction.Behaviors> 5 </Border>

1 private void DoubleTapGesture_DoubleTap(object sender, EventArgs e) 2 { 3 MessageBox.Show("Has hecho Doucble-Tap en el Border!"); 4 }

En este articulo hemos vistos los dos primeros gestos, en los siguientes iremos desmenuzando los gestos que nos quedan, os dejo el código del proyecto