Muchas aplicaciones de edición todavía utilizan Windows Forms. Y muchas de ellas (sobre todo si son prototipos rápidos o herramientas internas) utilizan el PropertyGrid como método rápido y eficiente para editar propiedades de objetos.
Una de las funcionalidades más utiles de los PropertyGrids, es la posibilidad de definir TypeEditors para las propiedades de un objeto, de forma que el sistema escogerá automáticamente un interfaz de usuario específico para editar su valor. .Net incluye por defecto algunos de ellos, como el ColorPicker o el DateTimePicker:
Cuando los TypeEditors por defecto no son suficiente, es una gran idea desarrollar tus propios editores, para hacer tus editores lo más eficientes posible. Por ejemplo, el selector de colores por defecto de .Net no permite escoger valores para el canal Alpha (transparencia). La solución es sencilla y fácil: podemos implementar nuestro propio editor que sí lo permita.
Ahora bien, ¿qué ocurre si queremos aplicar ese TypeEditor a todas las propiedades de un tipo definido en otra DLL?
Es un caso bastante frecuente. En mi entorno, por ejemplo, tengo mi propia clase para almacenar colores, llamada Color4, pero está definida en una DLL específica para operaciones matemáticas. Es una DLL muy básica que quiero mantener con el menor número de referencias posible, para evitar dependencias todo lo que pueda. Por este motivo, es imposible definir el TypeEditor en dicha DLL, ya que eso implicaría referenciar System.Windows.Forms, System.Drawing, y unas cuantas cosas más que no tienen que estar ahí. A fin de cuentas, es mi editor visual el que debe depender de Windows Forms, y no mi DLL de operaciones matemáticas. ¿La solución?
Inyección dinámica de editores de tipo
La solución es asignar el TypeEditor dinámicamente, programaticamente, o como queráis decirlo. En lugar de incluirlo en tiempo de compilación, con clásico código…
[EditorAttribute("Color4Editor", typeof(System.Drawing.Design.UITypeEditor))]
…lo añadiremos en tiempo de ejecución, algo posible gracias a la clase TypeDescriptor y su método AddAttributes.
Basta con invocar algo como lo siguiente el el inicio del programa:
TypeDescriptor.AddAttributes(typeof(Color4), new EditorAttribute(typeof(Color4Editor), typeof(UITypeEditor)));
De esta forma, mantenemos las DLLs limpias de referencias innecesarias, y solo dependeremos de Windows Forms y similares donde realmente se necesita: en el editor.
Listo !