Llevo un tiempo buscando una alternativa a CompositeUI, un buen Framework que me ha facilitado escribir unas cuantas aplicaciones.

En .NET Framework 3.0, Microsoft introdujo un  nuevo sistema de representación (WPF), junto con un nuevo modelo para la construcción de aplicaciones en donde la parte visual de los componentes de la interfaz de usuario típicamente se define utilizando un lenguaje de marcado denominado xaml, al estilo de html. Mediante dicho lenguaje, además, se pueden utilizar las avanzadas capacidades de enlazado a datos (Data Binding) que proporciona el framework.

Sin embargo, CompositeUI es previo a la introducción de las WPF y aunque se han realizado esfuerzos por compaginar ambos entornos, es difícil realizar una buena utilización de lo mejor de cada entorno a la hora de construir una aplicación.

El post de Rob Eisenberg sobre Caliburn (Excalibur) despertó mi interés, así que he estado estudiando un poco su código y la sensación que me ha producido es realmente buena.

El funcionamiento es sencillo, tal como se ve en la aplicación de ejemplo que viene con el código fuente.  El primer paso a realizar es inicializar el sistema, por ejemplo, en el constructor de la aplicación.

public App()
{
    ShellApplication.Start(
        new CustomConfiguration()
        );
}

El objeto suministrado construye una nueva instancia del contenedor a utilizar, en este caso, WindsorContainer, y configura el sistema registrando diversos servicios o componentes.

Entre dichos componentes se encuentra la clase ApplicationPresenter que define el presentador que utilizará la ventana principal de la aplicación (MainWindow) que queda registrado de la siguiente manera.

container.AddComponent("ApplicationPresenter",
    typeof(ApplicationPresenter), typeof(ApplicationPresenter));

A partir del momento que registramos un objeto en el contenedor podemos aprovechar todas las ventajas de la inyección de dependencias, también conocida como inversión de control (IoC).

De forma resumida, bajo inyección de dependencias, las clases de objetos definen que tipo de objetos o interfaces necesitan (dependencias), así como que eventos publican y a cuales desean suscribirse, siendo el contenedor el encargado de proveer a las instancias de los objetos con dichas dependencias. Estos sistemas presentan importantes ventajas desde el punto de vista de flexibilidad, escalabilidad y fiabilidad.

Caliburn provee de dos atributos para la gestión de eventos. Podemos publicar un evento del tipo Action<T> marcándole con el atributo Publish tal y como se ve en el ejemplo siguiente.

[Publish("event://NombreDelEvento")]
public event Action<object> Evento;

Y podemos recibir dicho evento en los objetos que nos interese simplemente definiendo un método que encaje con el delegado del evento, en este caso Action<object> y marcándole con el atributo Subscribe.

[Subscribe("event://NombreDelEvento")]
public void GestorDelEvento(object parametro)
{
    //Acciones a realizar cuando se produzca el evento
}

Cada vez que solicitemos un objeto al contenedor, este se encargará de realizar las gestiones necesarias para 'cablear' automáticamente los eventos.

Por último mencionar que podemos obtener objetos del contenedor utilizando el método estático Resolve. Por ejemplo, para obtener un objeto del tipo ApplicationPresenter previamente registrado utilizaríamos el siguiente código.

ApplicationPresenter presenter = 
    (ApplicationPresenter)Shell.Container
    .Resolve(typeof(ApplicationPresenter));

Caliburn también nos proporciona algunas extensiones de marcado para utilizar en xaml que nos permiten obtener una instancia de un presentador directamente desde una vista asignándole a la propiedad DataContext de la vista así como enlazar directamente ciertos componentes de la interfaz de usuario (botones y objetos de menú) a métodos públicos definidos en el presentador.