domingo, 3 de mayo de 2015

ASP.NET MVC. Personalizar el Motor de Vistas de MVC (I). Creando el escenario.

El Framework de ASP.NET MVC incorpora el motor de vistas Razor, el cual proporciona un formato de vistas muy flexible y potente. Sin embargo existen escenarios en los que puede resultar compleja definir nuestras vistas utilizando Razor.

Por suerte ASP.NET MVC está diseñado expresamente para permitir una gran flexibilidad y extensibilidad y, para estos casos, nos permite crear nuestro propio motor de vistas.

En esta serie de artículos voy a mostrar cómo podemos desarrollar nuestro propio motor de vistas integrado con el Framework de ASP.NET MVC.

Creando el escenario  de pruebas

Como comentaba existen situaciones en las que las vistas Razor pueden no ajustarse a las necesidades de nuestro proyecto. Imaginemos una aplicación que disponga de un diseñador de pantallas que genere diseños de pantalla en un formato propio, u otra en la que generemos formularios seleccionando los campos a mostrar a partir de información contenida en la base de datos.

Estos escenarios implicarían incluir complejo código en nuestras vistas o helpers.

Lo que voy a hacer es coger el primero de estos escenarios, una aplicación con vistas en un formato propio, y desarrollar un motor de vistas personalizado de forma que estas vistas se integren en el Framework MVC.

Para empezar he creado una nueva aplicación ASP.NET CustomViewEngine en Visual Studio, seleccionando la plantilla vacía y marcando el check para incluir las referencias a MVC.

Crear proyecto CustomViewEngine

Seleccionar plantilla vacía con MVC

He añadido una clase Persona en la carpeta Models que utilizaré como modelo de las vistas.


using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;

namespace CustomViewEngine.Models
{
    public class Persona
    {
        [Required]
        public string Nombre { get; set; }
        [Required]
        public string Apellido { get; set; }
        public string Ciudad { get; set; }
        [Display(Name = "Fecha de Nacimiento")]
        [DataType(DataType.Date)]
        public DateTime FechaNacimiento { get; set; }
        [Display(Name = "Último Acceso")]
        public DateTime UltimoAcceso { get; set; }
        [Display(Name = "Fecha de Registro")]
        [DataType(DataType.Date)]
        public DateTime FechaRegistro { get; set; }
        [Display(Name = "Última Operación")]
        public DateTime UltimaOperacion { get; set; }
    }
}
Imports System.ComponentModel.DataAnnotations

Public Class Persona
    <Required> _
    Property Nombre As String
    <Required> _
    Property Apellido As String
    Property Ciudad As String
    <Display(Name:="Fecha de Nacimiento")> _
    <DataType(DataType.Date)> _
    Property FechaNacimiento As DateTime
    <Display(Name:="Último Acceso")> _
    Property UltimoAcceso As DateTime
End Class

He creado la clase con propiedades con diferentes tipos de datos y he añadido algunos atributos de validación para poder comprobar cómo nuestras vistas son capaces de manejarlos.

A continuación voy a crear un par de vistas para editar instancias de la clase modelo Persona.

Para el ejemplo he elegido un formato de vistas muy simple. Se tratará de archivos xml con una colección de elementos field que identificarán las propiedades del modelo a mostrar en la vista. Estos elementos field tendrán un atributo obligatorio name que identificará el nombre de la propiedad a mostrar y un atributo opcional readonly que determinará si el campo se muestra o no en modo de edición.

He creado en mi proyecto una carpeta Screens que utilizaré como ubicación para las vistas xml.

La primera vista que voy a crear representará un formulario sencillo que permitirá la edición de las propiedades Nombre, Apellido y Ciudad del modelo Persona. Para ello añadiré un fichero xml llamado PersonaSimple.xml en la carpeta Screens.

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <field name="Nombre"/>
  <field name="Apellido"/>
  <field name="Ciudad"/>
</root>

La segunda vista que voy a crear definirá un formulario con todas las propiedades del modelo Persona marcando algunas de las fechas como de sólo lectura. Así que añadiré el fichero PersonaCompleto.xml a la carpeta Screens.

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <field name="Nombre"/>
  <field name="Apellido"/>
  <field name="Ciudad"/>
  <field name="FechaNacimiento"/>
  <field name="UltimoAcceso" readonly="true"/>
  <field name="FechaRegistro" readonly="true"/>
  <field name="UltimaOperacion" readonly="true"/>
</root>



Se pueden crear motores de vistas para gestionar vistas completas, vistas parciales o ambas. Un motor de vistas que gestione vistas completas deberá responsabilizarse de generar el código HTML completo de la página, incluido encabezado, carga de scripts, hojas de estilos, etc. Para simplificar el ejemplo el motor de vistas que voy a generará los formularios como vistas parciales, así que las vistas principales serán vistas tradiciones Razor.

Así que para acabar de preparar el proyecto de prueba voy a añadir un controlador HomeController en la carpeta Controllers con una única acción Index que se encargará de mostrar el formulario seleccionado a partir del parámetro Id.

using CustomViewEngine.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace CustomViewEngine.Controllers
{
    public class HomeController : Controller
    {
        public ViewResult Index(Persona persona, string Id = "PersonaSimple")
        {
            ViewBag.ScreenName = Id;
            return View(persona);
        }

    }
}
Imports System.Web.Mvc

Namespace Controllers
    Public Class HomeController
        Inherits Controller

        Function Index(persona As Persona, Optional Id As String = "PersonaSimple") As ViewResult
            ViewBag.ScreenName = Id
            Return View(persona)
        End Function

    End Class
End Namespace

La acción llama a la vista Index usando una instancia de la clase Persona como modelo. También pasan a través del objeto ViewBag el nombre de la vista xml a mostrar. Por lo tanto hará falta crear una vista Index:

@model CustomViewEngine.Models.Persona

@{
    ViewBag.Title = "Index";
}

@ViewBag.ScreenName
@ModelType CustomViewEngine.Persona
@Code
    ViewData("Title") = "Index"
End Code

@ViewBag.ScreenName

Esta vista simplemente muestra el nombre de la vista parcial xml a generar. Si arrancamos la aplicación y navegamos a las urls /Home/Index/PersonaSimple y /Home/Index/PersonaCompleto veremos que se muestran los nombres de las vistas PersonaSimple y PersonaCompleto.

Resultado en el navegador


Ya tenemos listo nuestro escenario.

En los siguientes artículos mostraré cómo desarrollar nuestro motor de vistas:



El código completo de este artículo y los tres siguientes, tanto en C# como en Visual Basic, está disponible en:

Crear un motor de vistas personalizado en ASP.NET MVC. - Ejemplos MSDN.

No hay comentarios:

Publicar un comentario