Con esta entrada se dará conclusión a la serie dedicada al análisis de código realizado sobre el proyecto didáctico “PuzleAnimales” disponible en el Canal Windows 7 Multitouch de Codeplex. En la serie se ha aportado información en mayor detalle para ayudar en la comprensión de los conceptos que son desarrollados a lo largo de toda la aplicación.

Como ya se comentó en la entrada anterior, Análisis de código de aplicaciones ejemplo MS Windows 7 Multitouch: Puzzle Animales II, en esta oportunidad se centrará la atención en el código del control de usuario llamado “UserControl1”, y que lleva consigo todas las funcionalidades importantes para dotar de movimiento a un objeto dentro del lienzo.
Uno de los aspectos más importantes con respecto al concepto anterior es la incorporación de las propiedades “Interactions Behaviors” dentro del código XAML para hacer uso de sus capacidades a la hora de trabajar con objetos con los cuales se van a interactuar.
<i:Interaction.Behaviors>
<ei:TranslateZoomRotateBehavior ConstrainToParentBounds="True">
</ei:TranslateZoomRotateBehavior>
</i:Interaction.Behaviors>
Llegado a este punto y para ver mejor el código que va por detrás de este control de usuario, en la siguiente imagen se muestra el esquema general de la clase que lo implementa.

Esquema de la clase UserControl1
Se puede apreciar que hay un conjunto importante de elementos, a los cuales es conveniente dar una definición para conocer cual es su aporte en el desarrollo de la aplicación.

Cuadro de propiedades y eventos de la clase UserControl1
· Ancho:
Margen de error vertical que se permitirá al intentar encajar una pieza en su lugar.
· Largo:
De forma análoga a la anterior, sería el margen de error horizontal al intentar encajar una pieza en su sitio.
· Handle:
Argumento que será usado por referencia en los métodos “midiOutClose” y “midiOutOpen “y “midiOutShortMsg”.
· Manejador:
Variable que reutiliza el contenido de “Handle” utilizando sus propiedades “Get” y “Set”, para obtener o establecer el valor de dicha variable respectivamente.
· Imagen:
En esta variable puede verse la ruta de la imagen que se muestra para el animal en cuestión, esta imagen está definida por el archivo “configuración.xml” y dispone de tres posibles valores.
· Padre:
Esta variable es quizás la más difícil de explicar, ya que es inicializada en uno de los constructores explícitos de UserControl1, y después cuando se lanza el evento “image1_TouchUp” se cambia el “sender” por el contenido de esta variable.
Sirve para identificar el objeto sobre el cual se está trabajando.
· Sonido:
Sonido que será reproducido cuando una pieza sea encajada en su posición correctamente.
· Sonidofinal:
Variable donde se guarda la localización del sonido que se emitirá cuando la ejecución se termine de forma exitosa.
· X:
Posición en el eje horizontal donde está situada la imagen.
· Y:
Posición en el eje vertical donde está situada la imagen.
· Coincidencia:
Este evento ha sido declarado para ser utilizado principalmente desde la clase que la instancia, para que de forma se sepa en cada momento que objeto se está manipulando en la interfaz.
public event EventHandler Coincidencia;
Después de definir el cometido de cada una de las variables de la clase, ahora toca el turno de las funciones, las cuales están descritas en el siguiente recuadro:

Cuadro de funciones disponibles en UserControl1
Como se puede apreciar existen 3 constructores, declarados en la clase “UserControl1”:
1. El primero es el constructor implícito, que inicializa el origen de la imagen1, con la imagen de un gato. Dicho elemento se encuentra en la carpeta “Images”, que forma parte del árbol de directorios de la aplicación.
public UserControl1()
{
InitializeComponent();
this.image1.Source = new BitmapImage(
new Uri(@"pack://application:,,,/PuzleAnimalTouch;
component/Images/gato.jpg"));
}
2. El segundo es un constructor explicito, que inicializa la fuente de la imagen1 y a su vez también da un valor inicial al sonido.
Al dar valor a “padre”, se está guardando el nombre de la imagen que se está creando, En el desarrollo de la aplicación se han declarado los nombres “imagen1” ,”imagen2”, ”imagen3” e ”imagen4” para las cuatro imágenes con las cuales se interactúa en la aplicación.
Sin duda un aspecto muy importante es la inicialización de las coordenadas X e Y, que identifican el lugar sobre el cual se empezara a dibujar la imagen sobre el lienzo.
Después de describir el constructor solo quedaría verlo en codigo:
public UserControl1(string fotoi, string sonidoi, double x, double y, string padre)
{
InitializeComponent();
this.x = x;
this.y = y;
this.padre = padre;
this.image1.Source = new BitmapImage(new Uri(@fotoi));
this.sonido = sonidoi;
}
3. El tercer constructor es un constructor explicito que requiere como argumento un entero pasado por referencia, con el cual se inicializa el manejador que hará uso este control de usuario a la hora de hacer llamadas a las funciones de sonido.
public UserControl1(ref int manejador)
{
this.handle = manejador;
InitializeComponent();
}
Funciones midiOutOpen, midiOutShortMsg , midiOutClose
Como ya se mencionaron en la entrada anterior, estas funciones son las encargadas de hacer llamadas a la API de Windows en relación con la manipulación de sonidos. Como puede se puede apreciar, es necesario hacer una importación de la librería “winmm.dll” que guarda relación con el Windows Media Player de Windows, ya que dichas funciones están implementadas externamente en dichas librerías.
[DllImport("winmm.dll")]
private static extern int midiOutOpen(ref int handle, int deviceID,
MidiCallback proc, int instance, int flags);
[DllImport("winmm.dll")]
protected static extern int midiOutShortMsg(int handle, int message);
[DllImport("winmm.dll")]
protected static extern int midiOutClose(int handle);
Funciones “Image1_ImageFailed”, “UserControl_loaded”
La primera función se produce cuando hay un error asociado a la recuperación o formato de la imagen. En esta oportunidad ha sido implementada pero se ha dejado vacio, por si se os ocurre capturar el error de recuperación y hacer alguna operación adicional cuando suceda el citado error , o cualquier otra operación que consideréis conveniente.
En el caso del “UserControl_loaded”, es la función principal que se ejecuta cuando se carga un control de usuario, en este caso también se ha dejado en blanco, ya que no era necesario inicializar ningún valor, aparte de los que ya se hacían en el constructor.
Función Image1_touchUp() y función lanza()
Estas funciones son llamadas por el evento “TouchUp” y “MouseLeftButtonUp” respectivamente, y realizan la comprobación de que si la pieza ha sido soltada en las proximidades del lugar correcto (la proximidad se ajusta en las variables “alto” y “ancho”), se desencadena el evento “coincidencia” y se reproduce el sonido final correspondiente a la ruta que se encuentra alojada en la variable “sonidoFinal”.
Apreciar que en el código, se emplea un objeto “WindowsMediaPlayer” que servirá para reproducir el sonido que se le haya pasado a su propiedad URL.
// Si al soltar al animal, la posición del elemento se acerca mucho a la posición
// correcta, entonces se desencadena el evento coincidencia, y se reproduce el
// sonido final
if (((e.GetPosition(null).X > x) && (e.GetPosition(null).X < (x + largo))) && ((e.GetPosition(null).Y > y) && (e.GetPosition(null).Y < (y + ancho))))
{
if (this.Coincidencia != null)
this.Coincidencia(padre, null);
this.image1.Visibility = System.Windows.Visibility.Hidden;
WMPLib.WindowsMediaPlayer Player;
Player = new WindowsMediaPlayer();
// La ruta del sonido tiene origen en la carpeta donde se está ejecutando la
// aplicación, es decir, la carpeta bin, por lo tanto debe tenerse en cuenta
// que los elementos de la carpeta sonido, de la raíz de la aplicación, deben
// ser copiados en la carpeta de resultado del proyecto, sino la ejecución
// fallará, ya que no se habrán encontrado dichos elementos.
string r = System.IO.Directory.GetCurrentDirectory();
r = r + sonidofinal;
string ruta = r;
Player.URL = @ruta; // Se le dice cuál es el archivo a reproducir
Player.controls.play(); // Se da la orden de reproducir el archivo.
}
Con esto se da por finalizado la explicación del código que se encuentra por detrás del proyecto “PuzleAnimales”, con el cual se sigue haciendo hincapié en incentivar la participación de los usuarios en el desarrollo de aplicaciones para MS Windows Multitouch.
Si deseáis ver la aplicación en funcionamiento, no perdáis la oportunidad de visitar Aplicaciones ejemplo para Windows 7 Multitouch: PuzzleAnimalTouch, que forma parte de un nutrido grupo de entradas del área de desarrollo centradas en este tipo de dispositivos.
Para acabar, recuerda que si quieres aprender mucho más sobre los secretos de los sistemas Microsoft Windows, te recomendamos leer el libro de Sergio de los Santos "Máxima Seguridad en Windows: Secretos Técnicos" , o siempre puedes suscribirte al Canal RSS de Windows Técnico para estar al día de las novedades e información técnica de interés.

------------------------------------------------------------------------------------------------------------------------
Análisis de código de aplicaciones ejemplo MS Windows 7 Multitouch: Puzzle Animales I
Análisis de código de aplicaciones ejemplo MS Windows 7 Multitouch: Puzzle Animales II
Análisis de código de aplicaciones ejemplo MS Windows 7 Multitouch: Puzzle Animales III
------------------------------------------------------------------------------------------------------------------------
Enviado
ago 11 2011, 06:17
por
Jhonattan Fiestas