127.0.0.1: Hogar dulce hogar

domingo, 31 de julio de 2011

[Evento] Clausura del Curso de Desarrollo de dispositivos móviles con .NET

 

Desde el pasado lunes 25 al jueves 28 de julio impartí, con Rodrigo Díaz el curso de desarrollo de aplicaciones móviles con .NET. El temario consistió en lo siguiente:

  • Windows Phone.
  • Introducción a C# 4.0
  • Aplicaciones para Windows Phone, con MVVM, Databinding e IsolatedStorage
  • Juegos con XNA para Windows Phone.
  • Cómo publicar tus aplicaciones/juegos en el Marketplace.

Así pues, antes de nada me gustaría dar las gracias a todas las personas que han asistido al curso, a La Seu de la Nucía por permitirnos usar sus instalaciones y a todas las personas que de un modo u otro han logrado que este curso haya podido realizarse.

WP_000151

Además, dentro de unos días (en cuanto disponga un rato) publicaré en el blog los apuntes para los alumnos.

viernes, 24 de junio de 2011

Usando Reflection para tener una única ventana modal personalizable.

 

Tenemos el siguiente escenario: Una aplicación (en este caso en WPF) que tiene varias ventanas modales. Cada ventana contendrá un UserControl único, que a su vez se construirá mediante una serie de parámetros determinados dependientes de lo que requiera el propio control.

El primer enfoque, que lo podemos  llamar a fuerza bruta, sería crear una ventana por cada control de usuario que tenga. El segundo enfoque, algo más fino, sería crear el UserControl antes de la ventana y ajustarlo mediante una propiedad para que lo cargue en el contenedor que le digamos a la ventana. No es lo más elegante, pero estamos instanciando el UserControl en casos particulares y no es algo muy genérico.

El tercer enfoque, que es el que propongo aquí, sería usar Reflection para que la propia ventana sea quien instancie el UserControl y nosotros sólo nos ocupemos de crear la ventana con los parámetros adecuados. Así no tenemos que estar pendiente de la creación del control en sí, sino simplemente de crear la ventana, decirle qué queremos mostrar y mostrarla al usuario.

Para ello, en primer lugar creamos una ventana en WPF. Luego, en el constructor insertaremos los siguientes parámetros:

- Primero, el tipo del control que se instanciará.

- Y después, un listado de parámetros:

  1. 1:  public ModalPropertyWindow(Type childrenType, params object[] logicObject)
  2.  2:          {
  3.  3:              InitializeComponent();
  4.  4:          }

Luego, lo que tenemos que hacer es instanciar el control que queremos con los parámetros que se requieran. Usaremos Activator.CreateInstance, que creará esa instancia con una serie de parámetros. Internamente recorre esa clase y busca un constructor que tenga la disposición de parámetros que le indicamos. Si no lo encuentra, evidentemente producirá una excepción:

  1. this.stackPanel2.Children.Add(Activator.CreateInstance(childrenType, logicObject) as UIElement);

Nótese que directamente añadimos la instancia creada a un StackPanel.

Por último, sólo tenemos que llamar a la ventana e instanciarla con el control que queramos:

  1. ModalPropertyWindow window = new ModalPropertyWindow(typeof(ClientControl), this.currentCliente, this.loggedUser);
  2. window.ShowDialog();

Y así para todas las ventanas que queramos. En resumen: una única ventana modal, todos los controles que queramos y no nos tenemos que preocupar de instanciar cada uno de forma particular.

viernes, 3 de junio de 2011

[EVENTO] Desarrollo de videojuegos para Windows Phone 7

Este verano participaré junto con Fernando Llopis y Rodrigo Díaz en un curso destinado a explicar las bases de la programación de videojuegos enfocadas en la plataforma Windows Phone 7. Será del 25 al 28 de Julio en la Seu Universitària de La Nucìa, en Alicante.

 

SEU Universitaria y Plaza / Crystalzoo © Guillermo Luijk

En el cursillo veremos desde una introducción a C#, hasta cómo programar en 2D y 3D para Windows Phone 7 y el sistema de publicación. De este modo tendremos una visión global de lo que significa hacer el desarrollo de un videojuego, desde la idea inicial hasta la publicación en un Marketplace.

Aquí tenéis la página del curso para que quien quiera, pueda asistir.

viernes, 8 de abril de 2011

[WPF/Silverlight] Binding de objetos relacionados en un ComboBox

 

Escenario: Tengo dos entidades relacionadas. La entidad A se relaciona con la entidad B a través de un identificador. Y lo que quiero es bindear eso, pero de modo que yo disponga en la interfaz de un combobox –o cualquier tipo de selección- que permita seleccionar todos los elementos. Entonces tenemos las siguientes tareas:

  1. Bindear los datos del campo con el identificador de la identidad.
  2. Pero yo no quiero ver un número. Yo quiero ver el nombre del objeto que relaciono. Por lo tanto, tendré un combobox que rellenar y bindear con respecto al identificador anteriormente citado.
  3. Y claro, para hacerlo bueno, bonito y barato, nada de hacerlo en el código. Todo debe ir en el XAML.

El primer enfoque puede ir dirigido a un binding normal. Es decir, obviamente tenemos que tener en cuenta el ID de la entidad A, puesto que ese será el valor elegido a mostrar. Y como quiero rellenar todo el combobox con el resto de entidades B, usaremos un Converter:

  1. <ComboBox ItemsSource="{Binding Converter={StaticResource ResourceKey=Converter}}" />

De este modo ya podemos ver todos los valores de la entidad B. Y además, en el converter podemos declarar cómo queremos mostrar cada Item:

  1. public class MyIDConverter : IValueConverter
  2.     {
  3.         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  4.         {
  5.  
  6.             List<ComboBoxItem> list = new List<ComboBoxItem>();            
  7.             foreach (B b in B.All())
  8.             {
  9.                 ComboBoxItem comboItem = new ComboBoxItem();
  10.                 comboItem.Content = b.Name;
  11.                 comboItem.Tag = b;
  12.                 list.Add(comboItem);
  13.             }
  14.             return list;
  15.  
  16.         }
  17.  
  18.         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  19.         {
  20.             return null;
  21.         }
  22.     }

Ahora lo que falta es enlazar el ID de A para que el combobox tenga como seleccionado el item de B correspondiente. Dentro del primero enfoque, sería usar otro converter para ello, pero tenemos un problema: necesito obtener el combobox para indicarle SelectedItem. De acuerdo, podemos declarar un parámetro en el Converter y le pasaremos el propio combobox del siguiente modo:

  1. <ComboBox ItemsSource="{Binding Converter={StaticResource ResourceKey=Converter}, ConverterParameter={RelativeSource Mode=Self}}" />

Pero esto directamente no compila. ¿Por qué? Porque los parámetros que se pasan al Converter deben ser constantes y no objetos variables. Es decir, le puedo pasar binding de propiedades como objetos ya que las considera “constantes”, pero el propio objeto comboBox (que al bindearlo se convierte en un puntero this) va cambiando. Una solución a esto es añadir manualmente dicho combobox como un DependencyProperty propio de la clase. Y otra solución es escribir el código necesario para que esto funcione en el codebehind. Pero recuerdo que el objetivo de esto es usar únicamente el XAML

¿Solución? El segundo enfoque. Simplemente consiste en añadir, además del primer Converter para rellenar el comboBox, otro que se dedique a bindear el contenido del combobox con el identificador de la entidad A. Se implementa la interfaz IMultiValueConverter que permite bindear a la vez varios elementos sobre una misma propiedad. De este modo, bindearemos la propiedad identificador de B que aparece en A como relación junto con el propio ComboBox. Y lo bindearemos al SelectedIndex de ComboBox, para que cargue el objeto B apropiado y además, que al seleccionar otro, modifique el identificador que corresponda.

Veamos el código:

  1. <DataTemplate>
  2.                             <ComboBox>
  3.                                 <ComboBox.ItemsSource>
  4.                                     <Binding Converter="{StaticResource ResourceKey=MyIDConverter}">
  5.                                     </Binding>
  6.                                 </ComboBox.ItemsSource>
  7.                                 <ComboBox.SelectedIndex>
  8.                                     <MultiBinding Converter="{StaticResource ResourceKey=MyIDtoIDConverter}" UpdateSourceTrigger="PropertyChanged">
  9.                                         <MultiBinding.Bindings>
  10.                                             <Binding Path="BID" Mode="TwoWay"></Binding>
  11.                                             <Binding RelativeSource="{RelativeSource Mode=Self}" Path="."></Binding>
  12.                                         </MultiBinding.Bindings>
  13.                                     </MultiBinding>
  14.                                 </ComboBox.SelectedIndex>
  15.                             </ComboBox>
  16.                         </DataTemplate>

Y ahora la implementación del IMultiValueConverter

  1. public class MyIDtoIDConverter : IMultiValueConverter
  2. {
  3.     private ComboBox combo;
  4.     public MyIDtoIDConverter()
  5.     {
  6.         combo = null;
  7.     }
  8.  
  9.     public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  10.     {
  11.         this.combo = values[1] as ComboBox;
  12.         ComboBoxItem comboItem = null;
  13.         int index = 0;
  14.         foreach (ComboBoxItem item in combo.Items)
  15.         {
  16.             OperationType operationType = item.Tag as OperationType;
  17.             if (operationType.Id == values[0] as int?)
  18.             {
  19.                 comboItem = item;
  20.                 combo.SelectedIndex = index;
  21.             }
  22.             index++;
  23.         }
  24.  
  25.         return combo.SelectedIndex;
  26.     }
  27.  
  28.     public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
  29.     {
  30.         ComboBoxItem comboItem = this.combo.Items[(int)value] as ComboBoxItem;
  31.         B b = comboItem.Tag as B;
  32.         return new object[] { b.ID };
  33.     }
  34. }

 

El Converter almacena el comboBox para que después al hacer el ConvertBack, tenga la referencia del estado de los items. De este modo, tenemos las entidades bindeadas con las propiedades de los elementos de WPF y además manteniendo sus relaciones.

miércoles, 6 de abril de 2011

[W7] Liberar puerto 80 en Windows 7

 

Normalmente para depurar cualquier website se suele emplear el propio puerto 80. En el caso de Azure, podemos tener el inconveniente de forzar el rol a que vaya en ese puerto pero por estar ocupado, se le asigna otro: 81, 82, y los siguientes.

Nuestro primer problema será liberar el puerto 80. Y para eso no hay nada como averiguar qué está ocupando dicho puerto. Lo primero es abrir la consola de comandos y escribir el siguiente comando que nos indicará qué puertos están actualmente a la escucha y el proceso asociado:

netstat –ab

image

Una vez viendo esto, podemos buscar el proceso a través del Administrador de Tareas y cerrarlo. El problema aquí puede ser lo que se aprecia en la imagen: no podemos ver qué proceso está ocupando el puerto 80. Evidentemente algo hay (es un proceso de sistema: podemos aplicar el comando netstat –anno para saber exactamente qué proceso es el que está ocupando el puerto), pero no nos indica nada. Y no hay ningún modo de saberlo.

Un modo de arreglarlo a fuerza bruta sería cancelar todos los servicios hasta que se libere el puerto. Pero es más fácil en nuestro contexto sin contamos con SQL Server. Simplemente, tenemos que deshabilitar los siguientes servicios y programas:

  • Skype: Suele ir por el puerto 80. Mejor no tenerlo activo.
  • IIS: Suele estar configurado para estar escuchando el puerto 80.

Y ahora empieza lo bueno, deshabilitando los siguientes servicios:

  • SQL Reporting Services: No aparece por ningún lado. Pero está camuflado bajo un proceso de sistema. Y funciona a través del puerto 80.
  • SQL Integration Services: Ídem del anterior.

Con esto, ya tenemos liberado el puerto 80 totalmente para nosotros:

image

domingo, 13 de marzo de 2011

[WP7] An update to Visual Studio is required to open Silverlight for Windows Phone

 

Este error me ha surgido al abrir mis antiguos proyectos para Windows Phone 7, incluso después de instalar todas las últimas actualizaciones de las Windows Phone Tools y reiniciar contínuamente. ¿La solución? Pues la encontré en el foro de desarrolladores.

Lo único que hay que hacer es volver a enlazar la dll de Design.Platform de nuevo a Visual Studio, para ello:

  1. Abrir la consola de comandos en modo administrador
  2. Ir hasta c:\ProgramFiles\Microsoft SDKs\Windows\v7.0A\bin\NETFX4.0. Si estás con Windows de 64 bits, entonces tienes que ir hasta ProgramFiles(x86).
  3. Ejecutar el siguiente comando: - gacutil /i "%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.Windows.Design.Platform.dll" /f. Del mismo modo que antes, si estamos con 64 bits debemos especificar la carpeta ProgramFiles(x86)
  4. Verificar que al ejecutar el comando, pone: "Assembly successfully added to the cache”.

Aquí dejo una captura de pantalla:

image

viernes, 4 de febrero de 2011

[C#] Instancias en runtime de tipos dinámicos

 

Durante el desarrollo de algunas herramientas es necesario generalizarlas para poder reutilizarlas posteriormente, pero manteniendo siempre una funcionalidad concreta. En el caso que nos ocupa, quiero poder listar una serie de atributos genéricos y poder operar con ellos en la precisión deseada, pero partiendo de la premisa anterior. Es decir, no tendré una clase que disponga de algo similar:

  1. public class A
  2.         {
  3.             int a;
  4.             float b;
  5.             int c;
  6.             UInt16 x;
  7.         }

Esto es muy costoso de mantener en futuros proyectos, puesto que estaría obligado a cambiar manualmente todos los atributos del objeto y sus nombres pese a que el comportamiento puede estar definido, puesto que sólo me interesa poder operar con los números.

¿Solución? Pues muy sencillo. Por un lado, vamos a almacenar únicamente el  nombre de atributo junto con su tipo y valor, todo con string. Posteriormente usaremos reflection para cargar el tipo de forma dinámica. Hasta aquí todo es correcto, nuestro mayor problema será que el evidentemente esos objetos dinámicos no son tipados y el compilador no sabrá qué son salvo que lo especifiquemos explícitamente mediante un casting. Es por ello que aquí entran los tipos dinámicos.

Los tipos dinámicos (o dynamic type, en inglés) es una nueva feature de C# 4.0. Recomiendo la lectura de la documentación para no caer en el error de confundirlos con los tipos anónimos. Debemos tener en cuenta que lo que queremos es operar con ellos en tiempo de ejecución, por lo que toda operación no soportada en tiempo de compilación por un tipo no nos servirá. De ahí que los tipos anónimos no sirva para el siguiente ejemplo, ya que no puedo operar entre objetos sin especificar explícitamente qué quiero hacer.

Es por ello que una vez tenemos el tipo deseado a instanciar mediante Reflection, podemos asignarle el valor y el tipo a la variable dinámica. Y podremos operar con ellos como si se tratase de tipos compilados previamente. Veamos un ejemplo:

  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             string uno = "1";
  6.             string dos = "2,5";
  7.  
  8.             dynamic a = Convert.ChangeType(uno, Type.GetType("System.Single"));
  9.             dynamic b = Convert.ChangeType(dos, Type.GetType("System.Single"));
  10.  
  11.             Console.Out.WriteLine(a);
  12.             Console.Out.WriteLine(b);
  13.             Console.Out.WriteLine(a+b);
  14.             Console.Out.WriteLine(a-b);
  15.             Console.Out.WriteLine(a*b);
  16.             Console.Out.WriteLine(a/b);
  17.             Console.ReadLine();
  18.         }
  19.     }

A través de Type.GetType() uso Reflection para cargar el tipo que quiero instanciar. Con Convert.ChangeType asigno un valor a un tipo, y todo ello a una variable dinámica. De este modo podremos operar con los números como si se tratasen de floats.