Muchos de los desarrolladores que a diario desarrollamos para el ecosistema Windows utilizamos el patrón Model-View-Viewmodel en nuestras aplicaciones, con ello y para facilitarnos dicho desarrollo gran parte utilizamos algún tipo de framework que nos ayude a implementar este patrón y así ahorrarnos parte del trabajo y del tiempo necesario. Uno de los más conocidos es Caliburn.Micro y es el que personalmente más he utilizado. Con la llegada de Windows 10 y las aplicaciones universales, las personas detrás de este framework han incluido el soporte para esta plataforma en la nueva versión. Dicha versión será la 3.0 y a parte de soportar aplicaciones universales también incluirá soporte para Xamarin. A día de hoy todavía no está disponible la versión final pero ya contamos con una beta disponible a través de Nuget con la cual podemos empezar a trabajar.

Vamos a ponernos manos a la obra, lo primero que debemos de hacer es crear un nuevo proyecto universal de Windows y añadirle la referencia a Caliburn.Micro. Debido a que es una versión beta tenemos que añadirla a través de la consola de administración de paquetes mediante el siguiente comando:

PM> Install-Package Caliburn.Micro -Pre

El proyecto nos deberá de quedar parecido a este:

Lo siguiente que tenemos que hacer es modificar el fichero App.xaml para que utilice la clase Application de Caliburn con lo que nos quedará así:

<micro:CaliburnApplication
    x:Class="CaliburnMicroW10.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CaliburnMicroW10"
    xmlns:micro="using:Caliburn.Micro"
    RequestedTheme="Light">
</micro:CaliburnApplication>

Caliburn.Micro realiza el binding entre la vista y el view model automáticamente pero para ello tenemos que seguir unas convenciones en los nombres de las carpetas y los archivos. Por ello vamos a borrar la pantalla MainPage.xaml que nos crea automáticamente Visual Studio y crear nuestra propia estructura de directorios. Tenemos que:

  • Crear dos carpetas: Views y ViewModels.
  • Dentro de la carpeta ViewModels crear una nueva clase MainPageViewModel.cs.
  • Dentro de la carpeta Views crear una nueva página en blanco MainPageView.xaml.

Como ya habrás visto, todos los view models que creemos deberán de ir dentro de la carpeta ViewModels y todas las vistas deberán de ir dentro de la carpeta Views. Además de ello si queremos crear una estructura de directorios dentro de esas carpetas para tener más organizado todo, deberemos de replicar la misma estructura en las dos carpetas. Por último, la vista y el view model deberán de tener el mismo nombre seguido del sufijo View en el caso de la vista y del sufijo ViewModel en el caso del view model. Con todo esto conseguiremos que Caliburn haga el binding entre la vista y el view model sin que nosotros tengamos que hacer nada más.

La apariencia del proyecto en este momento debe de ser algo parecido a esto:

Lo siguiente que vamos a hacer es modificar el fichero App.xaml.cs con todo lo necesario para que Caliburn.Micro funcione.

sealed partial class App : CaliburnApplication
{
    private WinRTContainer _container;

    public App()
    {
        this.InitializeComponent();
    }

    protected override void Configure()
    {
        _container = new WinRTContainer();
        _container.RegisterWinRTServices();
        _container.PerRequest<MainPageViewModel>();
    }

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        DisplayRootView<MainPageView>(e);
    }

    protected override void PrepareViewFirst(Frame rootFrame)
    {
        _container.RegisterNavigationService(rootFrame);
    }

    protected override object GetInstance(Type service, string key)
    {
        return _container.GetInstance(service, key);
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        _container.BuildUp(instance);
    }
}

Como veis tenemos que sobrescribir varios métodos de CaliburnApplication. En el método Configure tenemos que configurar nuestro inyector de dependencias y registrar los view models y servicios que vayamos a utilizar. En este caso he utilizado el propio que viene incluido en Caliburn pero podríamos hacer uso de otro.

En el método OnLaunched tenemos que indicarle cual va a ser la vista que se muestre cuando se abra la aplicación. En este caso será MainPageView. En el método PrepareViewFirst registramos el navigation service en el contenedor de dependencias, esto nos permitirá hacer uso de el en nuestros view models más adelante. A continuación tenemos tres métodos más GetInstance, GetAllInstances y BuildUp los cuales son utilizados para resolver las dependencias en nuestra aplicación.

Como puedes ver la mayor parte del código que tenemos en esta clase está relacionado con el inyector de dependencias y su configuración. Si queremos hacer cosas más especificas a la hora de registrar nuestros view models o servicios podremos registrar singletons con container.Singleton<NombreDeLaClase> o implementaciones de una interfaz concreta con container.Singleton<NombreDeLaInterfaz, NombreDeLaImplementacion>().

Lo siguiente que vamos a hacer es implementar algo de funcionalidad en nuestro view model. Lo primero es hacer que extienda de la clase Screen.

public class MainPageViewModel : Screen

Esto nos va a proporcionar varias cosas que nos van a facilitar la implementación del patrón MVVM. La primera es una implementación de la interfaz INotifyPropertyChange, la cuál nos permitirá avisar a la vista de que el valor de una propiedad ha cambiado. La segunda son cuatro métodos los cuales podemos sobrescribir y que nos avisarán de los diferentes estados de la vista:

  • OnInitialize: nos avisará de que la vista se ha iniciado.
  • OnViewAttached: nos avisará de que el binding entre la vista y el view model se ha realizado.
  • OnActivate: nos avisará de que la vista se ha mostrado.
  • OnDeactivate: nos avisará de que la vista se ha ocultado.

A continuación vamos a añadir la propiedad Title de tipo string en el view model.

public string Title
{
    get { return "Título de nuestra vista"; }
}

Por último vamos a añadir un TextBlock en nuestra vista con el nombre Title. Esto nos permite que Caliburn haga su magia y mediante un binding nos muestre el valor de la propiedad Title de nuestro view model en el este TextBlock.

<Page
    x:Class="CaliburnMicroW10.Views.MainPageView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CaliburnMicroW10.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock x:Name="Title"/>
    </Grid>
</Page>

Si ejecutamos el proyecto podremos veremos algo similar a esto:

Con esto tendremos listo un ejemplo muy básico de Caliburn.Micro integrado en un proyecto de aplicación universal Windows 10. En el siguiente post explicaré más detalladamente gran parte de las cosas que nos ofrece Caliburn.Micro y cómo podremos navegar entre diferentes vistas.

Como siempre, puedes encontrar todo el código del ejemplo en mi GitHub desde donde lo puedes descargar, probar y modificar sin ningún problema.

Continúa leyendo la segunda parte.