Você está na página 1de 119

APLICACIÓN WEB CON ASP NET MVC 2

Aplicación web con ASP.NET MVC 2 ......................................................... 1


Aplicación web con ASP.NET MVC 2 – parte 2 .............................................. 6
Aplicación web con ASP.NET MVC 2 – parte 3 ............................................. 10
Aplicación web con ASP.NET MVC 2 – parte 4 ............................................. 16
Aplicación web con ASP.NET MVC 2 – parte 5 ............................................. 30
Aplicación web con ASP.NET MVC 2 – parte 6 ............................................. 42
Aplicación web con ASP.NET MVC 2 – parte 7 ............................................. 52
Aplicación web con ASP.NET MVC 2 – parte 8 ............................................. 64
Aplicación web con ASP.NET MVC 2 – parte 9 ............................................. 74
Aplicación web con ASP.NET MVC 2 – parte 10 ........................................... 88
Aplicación web con ASP.NET MVC 2 – parte 11 ........................................... 93
Aplicación web con ASP.NET MVC 2 – parte 12 – Reportes en PDF.................. 106
Aplicación web con ASP.NET MVC 2 – Estilos en nuestras tablas..................... 114

i
Aplicación web con ASP.NET
MVC 2
Hace un año empezamos a trabajar con aplicaciones web con ASP.NET MVC 2 en Visual Studio 2010,
en este curso nuevamente trabajaremos con esta tecnología aunque contamos ya con la versión 3
del ASP.NET MVC, podremos pasar a la versión 3 no sin antes haber trabajado con la versión 2 y como
la red de la escuela no nos permite descargar no podemos actualizar nuestro Visual Studio.
Aún se encuentra la publicación del ejemplo anterior en http://afelipelc.mx/2011/05/23/mi-primera-
aplicacion-asp-net-mvc-2-paso-a-paso/ del cual se retomarán algunos datos pero en esta ocasión el trabajo
será diferente.

Actualmente en el sitio oficial de ASP.NET MVC http://www.asp.net/mvc/ encontramos el tutorial para


crear una aplicación con la versión 3 del ASP.NET MVC, pero aún se encuentran vivos los enlaces del
tutorial de ASP.NET MVC 2 que se tomó para realizar el ejemplo anterior, el link
eshttp://www.asp.net/mvc/tutorials/getting-started-with-mvc-part1.
Para saber más acerca de ASP.NET MVC, visita el sitio http://msdn.microsoft.com/es-
es/library/dd394709.aspx.
Nuestra aplicación de ejemplo a realizar consiste en crear una pequeña aplicación que administre los
diferentes grupos de alumnos de una escuela considerando: Programas educativos, cuatrimestres, grupos,
tutores y alumnos; debe considerarse que la información cambia constantemente como al cambiar un
nuevo año, nuevo cuatrimestre, cambio de grupo, tutores, etc. para ello debemos considerar también un
historial para que al iniciar un nuevo cuatrimestre los grupos puedan ser reiniciados a 0 alumnos, al igual
que deben considerarse los registros de las distintas generaciones (¿Suena algo complejo?, podría serlo
pero le daremos solución).

Por ahora la tarea es realizar el modelado de datos para nuestra aplicación.

Por otra parte, empezaremos con la parte de crear un primer proyecto de ASP.NET MVC 2.
Requisitos: Visual Studio 2010 con Visual Web Developer y SQL Server Express 2008. Para este
ejemplo se está utilizando Visual Studio 2010 versión Ultimate.
Crear un proyecto de Aplicación Web de ASP.NET MVC 2
En Visual Studio -> Crear nuevo Proyecto -> C# /Web >> elegimos Aplicación web de ASP.NET MVC
2, elegimos donde guardarlo y le ponemos el nombre de EscuelaWebApp (cambia el nombre si lo
prefieres).

1
Img. 1. Crear el proyecto
Al crear el proyecto nos pregunta si queremos crear un proyecto de prueba unitaria, por ahora elegimos
NO y damos clic en Aceptar.

¿Qué nos genera el proyecto?


El tipo de proyecto seleccionado nos crea 2 controladores, uno llamado HomeController que es la entrada
principal de la aplicación, y otro controlador llamado AcountController que se encarga de la gestión de
las sesiones de usuarios.

Img 2. Estructura de la aplicación.


Además de que crea toda la estructura del proyecto: Carpeta de Datos (App_Data), Carpeta de hojas de
estilo y otros contenidos (Content), Carpeta de Controladores (Controllers), Carpeta de vistas (Views)
donde se incluyen vistas compartidas como la plantilla del sitio llamada Site.Master y otros controles
como el de Usuario, Carpeta de modelo de datos y clases a utilizar como modelo (Models), Carpeta para

2
scripts JS (Scripts) que incluye por default JQuery y otras librerias y los archivos de configuración de la
aplicación.

Si se elige un proyecto de Aplicacion web vacía de ASP.NET MVC 2 creará solo la estructura sin el
controlador AcountController.
El controlador HomeController
El controlador Home es el punto de entrada para nuestra aplicación, si analizamos el código vemos que
contiene:

public class HomeController : Controller


{
public ActionResult Index()
{
ViewData["Message"] = "ASP.NET MVC";
return View();
}
public ActionResult About()
{
return View();
}
}
Encontramos que la clase HomeController contiene una Acción (ActionResult) llamada Index() que es la
acción por defecto en un controlador, es decir, si ejecutamos nuestra aplicación, obtendremos en el
navegador que nos muestra la página principal en la direccion http://localhost/ lo que vemos ahí es el
resultado de la llamada a la acción Index() del controlador Home, en el ejemplo, la acción Index() pasa
un parámetro llamado “Message” a la vista relacionada (Index.aspx en View/Home) a la acción por
medio de ViewData[“Message”] cuyo valor será mostrado por la vista en el navegador.
Todas las acciones de un controlador deben devolver una vista por medio de return View(), entonces para
cada acción puede crearse una vista que deberá llevar el mismo nombre (más adelante veremos las vistas),
pero también puede una acción devolver otra vista con nombre diferente, como cuando queremos mostrar
la misma vista al usuario en caso de generase un error, devolveremos la vista llamada Error.aspx que se
encuentra en Views/ Shared.
La acción About() solo responde con la vista relacionada llamada About.aspx que se encuentra en
Views/Home.
Entonces podemos darnos cuenta que para cada controlador se crea una carpeta en Views donde se
encontrarán todas las vistas asociadas a las acciones de cada controlador.

Podemos decir también que las acciones tiene la estructura:

public ActionResult NombreDeLaAccion()


{
//Todas las sentencias que deberá ejecutar la acción.
//Generar un resultado si fuera el caso
//Devolver la vista con el resultado generado

3
return View();
}

Las acciones pueden recibir parámetros de lo que veremos más adelante.


Analicemos ahora el código de la plantilla del sitio llamada Site.Master (en Views/ Shared) (no puede
agregarse aquí en la publicación porque wordpress.com no lo permite)
Encontramos que la mayor parte del código es HTML.

Lo que nos llama la atención es

<title> <asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>

donde encontramos la etiqueta ASP llamada ContentPlaceHolder con el Id TitleContent, cuya función es
poner en ese espacio el título de la página proporcionado por las vistas, lo mismo que donde deberá
insertarse el contenido de la página (pasado por la vista).
La estructura del sitio creada por la plantilla es el siguiente:

Img. 3. Estructura del sitio.


Analicemos ahora el código de la vista Index.aspx

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Página principal
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2><%:ViewData["Message"] %>
<p>
Para obtener más información sobre ASP.NET MVC, visite el < a href="http://asp.net/mvc" title="sitio web de
ASP.NET MVC">http://asp.net/mvc.

4
</p>
</asp:Content>

Podemos encontrar que contiene la etiqueta ASP llamada Content con un identificador y especifica
el ContentPlaceHolderID donde deberá mostrarse la información que recide dentro de esta etiqueta, para
í ContentPlaceHolderID=”TitleContent” el contenido a mostrar es “Página principal” que en sí es el
título que le estamos dando a nuestra página.
Para el ContentPlaceHolderID=”MainContent” es todo el contenido de nuestra página, en este caso
mostrará el valor que contiene el parámetro “Message” pasado por la acción Index() del controlador
Home, donde observamos que para imprimir el valor de una variable, parámetro o datos del modelo se
hace por medio de <%:NombreElemento%> ejemplo: <%:ViewData[“Message”] %>, el contenido
también incluye un poco más de información contenida en un párrafo.
Ejecutando nuestro proyecto, VS abrirá el navegador web mostrando el resultado:

Img. 4. Vista de la ejecución de la aplicación.


Debemos considerar que como no estamos utilizando nuestro propio servidor IIS para la ejecución de
nuestras aplicaciones web, VS esta utilizando el IIS de desarrollo que trae integrado, por ello a cada
aplicación web le asigna un puerto, para mi aplicación le ha asignado el puerto 2958 en el cuál esta
corriendo la aplicación y cada vez que se quiera ingresar a ella (mientras se este ejecutando),
debe hacerse por medio de este puerto.

Pues bien, hasta aquí es solo lo que nos ha generado el Visual Studio al crear nuestro proyecto, en el
siguiente avance agregaremos algunos controladores y vistas para ir avanzando en el desarrollo.

¿Algún comentario o información que agregar?, puedes colaborar.

5
Aplicación web con ASP.NET
MVC 2 – parte 2
Continuando con el desarrollo de nuestra aplicación, primero debemos tener nuestro modelo de datos para
que posteriormente agreguemos los controladores, acciones y vistas correspondientes, para ello se
propone la siguiente estructura para la base de datos.

Img. 1. Diagrama relacional de la BD.


Agregar la base de datos al proyecto.
Para agregar la base de datos al proyecto, nos ubicamos sobre la carpeta App_Data (en el explorador de
soluciones) donde con el botón de derecho del ratón elegimos Agregar / Nuevo elemento, en la ventana
para agregar nuevo elemento nos ubicamos sobre las plantillas C# / Datos donde seleccionamos Base de
datos SQL Server, el nombre para nuestra base de datos será BDEscolar.mdfy hacemos clic en Agregar
como se aprecia en la imagen.

6
Img. 2. Agregar la base de datos al proyecto.
Agregada la base datos aparecerá en nuestro explorador de soluciones.

Img. 3. Base de datos agregada al proyecto.

Img. 4. Explorador de servidores mostrando las tablas de la BD.

7
Ahora abra la base de datos, haciendo doble clic sobre ella, VS nos mostrará el explorador de servidores,
donde deben crearse las diferentes tablas contenidas en el diagrama (img. 1), considere los tipos de datos
apropiados donde las claves primarias sean definidas como identidad con auto incremento en 1 excepto el
campo Alumno.Matricula que será definido por el administrador, recuerde también crear las relaciones
correspondientes (puede consultar el modelo mostrado en la img. 7 donde se muestran mejor las
relaciones y su cardinalidad) para que posteriormente creemos el modelo de datos y este sea correcto.
Crear el modelo de datos.
Ya con nuestra base de datos, creemos ahora nuestro modelo conceptual de datos, para ello utilizaremos
el ADO.NET Entity Framework, para obtener más información acerca de este Framework,
visite http://msdn.microsoft.com/es-mx/data/aa937723 consulte también el siguiente
enlace http://msdn.microsoft.com/en-us/library/bb399572.aspx que contiene información
sobreADO.NET EF.
Entonces para crear nuestro modelo de datos utilizaremos el elemento ADO.NET Entity Data Model para
ello consulte el enlace http://msdn.microsoft.com/en-us/library/bb399249.aspx que contiene información
acerca de este componente y las diferentes herramientas que se utilizarán posteriormente (por ejemplo el
asistente para crear el modelo).
Ya para no marear más, en la carpeta Models en el menú contextual(clic derecho) elegimos Agregar /
Nuevo elemento, en la ventana para agregar el nuevo elemento nos situamos sobre las plantillas C# /
Datos donde seleccionamos ADO.NET Entity Data Model el cual le pondremos el nombreModeloDatos.

Img. 5. Agregar el ADO.NET Entity Data Model.


Seguimos el asistente donde en el primer paso (Elegir contenido de Model) seleccionamos Generar desde
la base de datos.

En el segundo paso veremos que automáticamente nos muestra nuestra base de datos BDEscolar.mdf (si
no la muestra debemos crear la conexión hacia nuestro archivo de base de datos), seleccionada la base de
datos nos muestra la cadena de conexión que se almacenará en el archivo Web.Config del proyecto, a la
cadena de conexión le asigna el nombre BDEscolarEntities (lo dejamos como tal) que utilizaremos como
clase para poder utilizar el modelo en nuestros controladores u otras clases.

8
En el tercer paso seleccionamos las tablas y otros elementos de nuestra BD que queremos agregar al
modelo, notemos que el espacio de nombres para el modelo es BDEscolarModel.

Img. 6. Elegir los objetos de BD a incluir en el modelo.


Seleccionadas las tablas a incluir finalizamos el asistente, donde obtendremos el resultado esperado.

9
Img. 7. Modelo de datos para nuestra aplicación.
En el modelo conceptual observamos que se han creado correctamente las propiedades de navegación,
para saber más acerca de las propiedades de navegación visite el enlace http://msdn.microsoft.com/es-
es/library/ee382841.aspx
El siguiente avance será para agregar los controladores y empezar a crear y editar los primeros registros
de nuestra aplicación.

Cualquier comentario para complementar la información o aportar para mejorarla son bienvenidos.

Aplicación web con ASP.NET


MVC 2 – parte 3
Después de haber creado nuestra base de datos y el modelo de datos a utilizar en nuestra aplicación, antes
de agregar cualquier registro a las tablas es recomendable tener un respaldo de la BD vacía,
posteriormente si se le realiza algún cambio al diseño de la BD volver a crear un respaldo ya que al ir
realizando las pruebas de funcionalidad de la aplicación se irán agregando registros y para cuando la

10
aplicación esté terminada tendremos que limpiar la BD para que ahora sí empiece a trabajar desde cero,
entonces será más fácil reemplazar la BD con datos de prueba por la vacía.

Agregar los primeros datos a la BD.


Para empezar a realizar nuestros primeros avances, necesitamos contar con algunos datos en nuestra BD,
para ello agregaremos algunos registros a la tabla principal “ProgramaEducativo”.

Img. 1. Agregar los primeros datos manualmente.


Agregar controladores.
Ya con los datos en nuestra tabla, ahora agregaremos un nuevo controlador al proyecto, para ello en el
explorador de soluciones, hacemos clic derecho sobre Controllers y en el menú contextual seleccionamos
Agregar / Controlador, VS nos mostrará una ventana donde debemos ingresar el nombre del controlador,
en esta ventana vemos que en el cuadro de texto para el nombre aparece Default1Controller donde
“Default1″ aparece seleccionado, significa que ese es el nombre para el controlador, el nombre de un
controlador siempre debe llevar el sufijo “Controller” de esta forma VS identifica que se trata de un
controlador, entonces agregaremos un controlador llamado AdministrarPE que quedará como
“AdministrarPEController” (empezaremos por agregar los controladores para administrar los datos).

Img. 2. Agregar un nuevo controlador.


Podemos seleccionar la opción “Agregar métodos de acción para los escenarios Create, Update, Delete y
Details” y al crear el controlador se crearán estas acciones (pero con los nombres en inglés), en este caso
agregamos el controlador sin seleccionar esta opción.

Acceder al modelo desde el controlador.


Para que nuestro controlador pueda acceder al modelo, debemos agregar el using correspondiente.

11
using EscuelaWebApp.Models;

El propósito de este controlador es permitir al usuario (administrador) visualizar la lista de programas


educativos con la opción de agregar nuevos, editar y eliminar registros.

Entonces lo que haremos es que al ingresar a la url de nuestro controlador (localhost/AdministrarPE) el


Index nos muestre la lista de programas educativos.

Agregaremos el código correspondiente para que la acción Index() del nuevo controlador pase la lista de
programas educativos a la vista, para ello primero crearemos una instancia de nuestra conexión a la BD
(Modelo).

El código de nuestro controlador es el siguiente (no incluí aquí el código del namespace ni los using):

public class AdministrarPEController : Controller


{
//crear instancia del entity model (Base de datos)
BDEscolarEntities BD = new BDEscolarEntities();
//
// GET: /AdministrarPE/
public ActionResult Index()
{
//obtener la lista de programas educativos desde el modelo (BD)
var programaseducativos = BD.ProgramaEducativo.ToList();

//Pasar la lista de resultados a la vista


return View(programaseducativos);
}

}
Crear una nueva vista.
Es importante recordar que cada una de las acciones (ActionResult) debe devolver una vista (por lo
general con el mismo nombre) o redireccionar a otra acción que devuelva una vista.

Para crear una vista para una acción, sobre el nombre de la acción Index() presionamos botón derecho y
seleccionamos CrearVista esto nos abrirá una ventana donde:
1. Debemos especificar el nombre para nuestra vista (mismo nombre de la acción).
2. Como queremos que el Index nos muestre la lista de programas educativos, seleccionamos
“Crear una vista fuertemente tipada” donde en “Clase de datos de View” seleccionamos la
clase “Programa educativo”.
3. En Contenido de view seleccionamos el contenido para nuestra vista, como queremos que
muestre una lista, seleccionamos “List”.
4. Las opciones de “Seleccionar la página maestra” la dejamos como tal, si fuera el caso que
tenemos diferentes plantillas debemos seleccionar la plantilla a utilizar.
5. Si cambiamos el contenedor principal donde debe mostrarse el contenido en nuestra plantilla,
debemos especificar su ID.
6. Agregamos la vista.

12
Img. 3. Agregar una vista fuertemente tipada.
Observamos que el código de la nueva vista mostrará como título “Index”, así que cambiamos el título a
“Programas Educativos”.

Vemos también que el código contiene una tabla en HTML con las columnas correspondientes a los
campos de la tabla “ProgramaEducativo” y una primera columna que mostrará los links correspondientes
para Editar, Detalles y eliminar cada uno de los registros.

Observemos que para mostrar los datos de los PE registrados nuestra vista los escribirá en la tabla
utilizando un foreach que recorre los elementos contenidos en el Modelo (lista de objetos pasados por el
controlador).

Contiene al final también un enlace para crear un nuevo registro.

Consideremos que los enlaces que se muestren en nuestra página aún no funcionan, ya que los enlaces
apuntan hacia las acciones Create, Edit, Details y Delete que no existen en nuestro controlador (más
adelante crearemos las nuestras, por ahora lo dejamos así).

Código de la vista Index.aspx


<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Programas Educativos
</asp:Content>

13
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Lista de programas educativos.</h2>

<table>
<tr>
<th></th>
<th>
IdPE
</th>
<th>
Nombre
</th>
<th>
NombreCorto
</th>
</tr>

<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=item.IdPE }) %> |
<%: Html.ActionLink("Details", "Details", new { id=item.IdPE })%> |
<%: Html.ActionLink("Delete", "Delete", new { id=item.IdPE })%>
</td>
<td>
<%: item.IdPE %>
</td>
<td>
<%: item.Nombre %>
</td>
<td>
<%: item.NombreCorto %>
</td>
</tr>

<% } %>

</table>

<p>
<%: Html.ActionLink("Create New", "Create") %>
</p>

</asp:Content>
Ejecutemos nuestra aplicación e ingresemos a la ruta de nuestro controlador, en mi caso
es http://localhost:2958/AdministrarPE (recuerda que 2958 es el puerto que el IIS de desarrollo asigna a
nuestra aplicación).

14
Img. 4. Nuestra primera vista mostrando la lista de programas educativos.
Y ese es el resultado que tenemos hasta ahora, vaya que es rápido desarrollar aplicaciones web con esta
tecnología, pero apenas estamos empezando :D

Los Links (ActionLink)


Vemos que nuestra aplicación muestra algunos enlaces y si navegamos por el código de nuestra vista o
Site.Master donde genera los links vemos que se utiliza Html.ActionLink.

¿Cómo se generan los vínculos o links?


Ejemplos de links:

1. <%: Html.ActionLink(“Acerca de”, “About”, “Home”)%>


2. <%: Html.ActionLink(“Programas educativos”, “Index”, “AdministrarPE”)%>

3.
4. <%: Html.ActionLink(“Edit”, “Edit”, new { id=item.IdPE }) %>
5. <%: Html.ActionLink(“Details”, “Details”, new { id=item.IdPE })%>
6. <%: Html.ActionLink(“Delete”, “Delete”, new { id=item.IdPE })%>
Por medio de Html.ActionLink genera los vínculos a acciones de un controlador, por ejemplo el link 1)
genera el enlace http://localhost:2958/Home/About, el 2) genera el
enlace http://localhost:2958/AdministrarPE/ el 3)
genera http://localhost:2958/AdministrarPE/Edit/Xnúmero, etc. nótese que no se pone la palabra
“Controller” en Home, AdministrarPE (nombre de los controladores), entonces la sintaxis es:

Cuando estamos llamando a una acción en el mismo controlador.


<%: Html.ActionLink(
"Acceso externo", // Texto del enlace
"Editar", // Acción
new { id=Model.Id } // Parámetros
)

15
%>
Esta sintaxis es la utilizada en los links 3, 4 y 5 porque solo se están mostrando y utilizando en las vistas
del controlador AdministrarPE.

Y cuando queremos acceder a la acción de otro controlador


<%: Html.ActionLink(
"Acceso Externo", //Texto del enlace
"Editar", // Acción
"Productos", // Nombre del controlador
new { id=Model.Id } // Parámetros
) %>
Por Ejemplo cuando en la página principal queremos que se muestre un enlace para acceder algún
determinado controlador (otro nivel), realizaremos algo como

<%: Html.ActionLink(“Programas educativos”, “Index”, “AdministrarPE”)%>

Vaya a Site.Master y en el div que contiene el menú, agrege el código para generar el enlace.

Ejecutamos nuestra aplicación donde en la página principal y por toda la aplicación podremos ver nuestro
nuevo link.

Img. 5. Resultado de agregar un nuevo link a la plantilla Site.Master.


Ahora podemos acceder rápidamente a nuestra nueva sección de nuestra aplicación.

Ya para no aburrir más con esto de la aplicación aquí paramos esta lección, continuaremos con la parte de
agregar, editar y eliminar en la siguiente entrega.

Aplicación web con ASP.NET


MVC 2 – parte 4
16
En la parte 3 del tutorial solo vimos acerca de los controladores, las vistas y los enlaces, donde el trabajo
realizado fue solo agregar la acción Index al Controlador AdministrarPE la cual al ser invocada muestra
la lista de registros almacenados en la tabla correspondiente.

Img. 1. Resultado del trabajo anterior (parte 3).


Ahora es esta parte del tutorial veremos como crear las acciones que permitan crear un nuevo registro,
editar y eliminar un existente.
Las acciones Registrar, Editar y Eliminar.
Ahora trabajaremos en la Acción Registrar de la que tendremos 2 direcciones (GET y POST) las cuales
son indispensables cuando se trata de acciones donde se ven involucradas la solicitud e ingreso de datos a
la aplicación.

La acción Registrar (GET)


Se habla de GET porque la acción responde a nuestra petición cuando intentemos crear un nuevo registro
(solo atiende peticiones GET), es decir, la parte GET solo se encargará de mostrarlos el formulario
correspondiente el cual en su propiedad Action estará enlazada a una acción llamada Registrar que
recibirá los datos ingresados en el form.

// GET: /AdministrarPE/Registrar
public ActionResult Registrar()
{
return View();
}
Ahora creemos la vista correspondiente:

Cree una nueva vista con el nombre Registrar donde:

 Seleccione “Crear una vista fuertemente tipada” seleccionando la clase ProgramaEducativo.


 En contenido de view, seleccione la opción Create.
 Creada la vista, modifique el código para que muestre la leyenda o titulo correspondiente.

17
Img. 2. Crear vista para Registrar.
Modifiquemos ahora el código de la vista, como el campo IdPE de PrgramaEducativo es auto incremento,
eliminemos el código HTML del form que corresponde al campo para ingresar el valor de IdPE, mostrar
la leyenda y textos correspondientes y modificar el link que lleva al index, el código de la vista quedaría
así:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Registrar un nuevo programa educativo
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Registrar nuevo programa educativo.</h2>

<% using (Html.BeginForm()) {%>


<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>Datos del programa educativo</legend>

<div class="editor-label">
<%: Html.LabelFor(model => model.Nombre) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Nombre) %>
<%: Html.ValidationMessageFor(model => model.Nombre) %>
</div>

18
<div class="editor-label">
<%: Html.LabelFor(model => model.NombreCorto) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.NombreCorto) %>
<%: Html.ValidationMessageFor(model => model.NombreCorto) %>
</div>

<p>
<input type="submit" value="Registrar programa educativo" />
</p>
</fieldset>

<% } %>

<div>
<%: Html.ActionLink("Regresar a la lista de programas educativos",
"Index") %>
</div>

</asp:Content>
Ahora ingresemos manualmente a nuestra acción en http://localhost:2958/AdministrarPE/Registrar donde
vemos el formulario.

Img. 3. Formulario para crear un nuevo registro (Vista Registrar).


Si llenamos el Form e intentamos registrar el PE, no funcionará ya que ninguna acción en nuestro
controlador recibe los datos.

La acción Registrar (POST)


Se comentó que esta acción será la encargada de recibir los datos del form (solo atiende peticiones
POST), en sí se trata de un nuevo objeto de la clase ProgramaEducativo.

Las acciones encargadas de recibir datos por POST se les antepone [HttpPost ] antes de la declaración,
nuestra acción Registrar (POST) quedaría así:

19
[HttpPost]
public ActionResult Registrar(ProgramaEducativo programaeducativo)
{
BD.AddToProgramaEducativo(programaeducativo);
BD.SaveChanges();

//agregado el registro (objeto), redireccionar al inicio del


controlador (Index).
return RedirectToAction("Index");
}
Esta acción agregará el nuevo objeto y automáticamente nos redireccionará a la lista de PE (por lo que no
se necesita crear una vista especial), notese que no se hace ninguna validación de los datos, si lo hubiera y
en el caso de que los datos sean incorrectos, se deberá mostrar la misma vista Registrar donde en el
formulario se muestren los datos ya ingresados y notificar al usuario los datos incorrectos para que pueda
corregirlo y volver a intentar crear el registro.

Ahora ejecute nuevamente la aplicación y vuelva al form anterior, llene los datos y cree el registro para
que pueda ver el resultado.

Img. 4. Creando un nuevo registro.


Después de hacer clic en el botón, tenemos el resultado.

20
Img. 5. Registro agregado.
Ahora en la vista Index, modifique el enlace “Create new” para que apunte a nuestra acción Registrar:

<%: Html.ActionLink(“Registrar nuevo Programa educativo”, “Registrar”) %>

La acción Editar
De igual forma como la acción Registrar, deben considerarse las peticiones GET y POST.

La acción Editar (GET)


La acción editar que atienda peticiones GET debe recibir como parámetro el ID del PE a editar, debe
buscar en la BD el objeto correspondiente y pasarlo a la vista para su edición, la vista debe mostrar en el
formulario con los datos correspondientes.

// GET: /AdministrarPE/Editar
public ActionResult Editar(int id)
{
//buscar el objeto en la BD
var programaeducativo = BD.ProgramaEducativo.Where(p => p.IdPE
== id).FirstOrDefault();

//si el registro existe, pasarlo al modelo


//sino, mostrar la vista Error (ubicada en Views/Shared/Error.aspx)
if (programaeducativo != null)
return View(programaeducativo);
else
return View("Error");
}
Notese que para realizar nuestra consulta en la BD utilizamos

var programaeducativo = BD.ProgramaEducativo.Where(p => p.IdPE


== id).FirstOrDefault();
Nota: aquí empezamos a trabajar con consultas LINQ y expresiones LAMBDA no nos meteremos con
estos temas, solo agregaré las consultas correspondientes pero sin explicarlas a fondo, para ello debe
estudiar por su propia cuenta estos temas (por si aún no está familiarizado), puede consultar el
enlace http://msdn.microsoft.com/en-us/library/cc161164.aspx que contiene buena información sobre
LINQ y http://msdn.microsoft.com/en-us/vcsharp/aa336746 que contiene 101 ejemplos de consultas
LINQ y algunos con expresiones Lambda, busque también más información en la web o en el sitio oficial
del MSDN.
Crearemos la vista correspondiente (en contenido de view ahora es Edit).

21
Img. 6. Crear la vista Editar (con contenido Edit).
Modificaremos el código de la vista donde agregaremos los textos correspondientes y el textbox
correspondiente al Id lo pondremos como solo lectura para que el usuario no pueda modificarlo.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Editar programa educativo.
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Editar: <%: Model.Nombre %></h2>

<% using (Html.BeginForm()) {%>


<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>Datos del programa educativo</legend>

<div class="editor-label">
ID
</div>
<div class="editor-field">
<% // Considerar poner el textbox del ID como solo lectura %>
<%: Html.TextBoxFor(model => model.IdPE, new
Dictionary<string, object>() { { "readonly", "true" } })%>
<%: Html.ValidationMessageFor(model => model.IdPE) %>
</div>

22
<div class="editor-label">
Nombre
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Nombre) %>
<%: Html.ValidationMessageFor(model => model.Nombre) %>
</div>

<div class="editor-label">
Nombre Corto
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.NombreCorto) %>
<%: Html.ValidationMessageFor(model => model.NombreCorto) %>
</div>

<p>
<input type="submit" value="Guardar Cambios" />
</p>
</fieldset>

<% } %>

<div>
<%: Html.ActionLink("Regresar a la lista de programas educativos",
"Index")%>
</div>

</asp:Content>
La acción Editar (POST)
Ahora creemos la acción Editar que reciba los nuevos datos y actualice la BD.

[HttpPost]
public ActionResult Editar(int id, FormCollection formValues)
{
//buscar el objeto en la BD
var programaeducativo = BD.ProgramaEducativo.Where(p =>
p.IdPE == id).FirstOrDefault();

//Actualizar los datos del objeto con los recibidos del form.
UpdateModel(programaeducativo, formValues);

//guardar los cambios


BD.SaveChanges();

//redireccionar al inicio del controlador (acción Index).


return RedirectToAction("Index");
}
Modificar la vista Index
Recordemos que en la lista de PE´s (Vista Index), muestra en cada registro un enlace con el texto “Edit”,
debemos modificar el ActionLink para que apunte hacia nuestra nueva acción:

<%: Html.ActionLink(“Editar”, “Editar”, new { id=item.IdPE }) %>

Ejecutemos nuestra app e intentemos editar un registro,


ejemplo: http://localhost:2958/AdministrarPE/Editar/1

23
Img. 7. Vista de la lista con el nuevo link Editar.

Img. 8. Editar los datos del programa educativo.


Guardados los cambios:

24
Img. 9. Datos guardados.
Eliminar Registros.
Ahora crearemos la acción que elimine los registros.

// GET: /AdministrarPE/Eliminar
public ActionResult Eliminar(int id)
{
//buscar el objeto en la BD
var programaeducativo = BD.ProgramaEducativo.Where(p =>
p.IdPE == id).FirstOrDefault();

//si el registro existe, pasarlo al modelo


//sino, mostrar la vista Error (ubicada en Views/Shared/Error.aspx)
if (programaeducativo != null)
return View(programaeducativo);
else
return View("Error");
}
Crear la vista correspondiente con contenido Delete.

25
Img. 10. Crear vista con contenido Delete.
Modificar el código de la vista (puede utilizar el diseñador):

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Eliminar programa educativo
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Eliminar: <%: Model.Nombre %></h2>

<h3>¿Está seguro que quiere eliminar el Programa Educativo?</h3>


<fieldset>
<legend>Datos del programa educativo</legend>

<div class="display-field"><strong>Id</strong>: <%: Model.IdPE %></div>

<div class="display-field"><strong>Nombre</strong>:
<%: Model.Nombre %></div>

<div class="display-field"><strong>Nombre Corto</strong>:


<%: Model.NombreCorto %></div>

</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Si Eliminar" /> |
<%: Html.ActionLink("Cancelar", "Index") %>

26
</p>
<% } %>

</asp:Content>
Crear la acción Eliminar para confirmar la eliminación.

[HttpPost]
public ActionResult Eliminar(int id, string confirmar)
{
//buscar el objeto en la BD
var programaeducativo = BD.ProgramaEducativo.Where(p =>
p.IdPE == id).FirstOrDefault();

//si el registro existe, eliminarlo


if (programaeducativo != null)
{
BD.DeleteObject(programaeducativo);
BD.SaveChanges();
return View("Eliminado");
}
else
return View("Error");
}
Al ser invocada la acción Eliminar por medio de una petición POST, buscará el objeto, lo eliminará de la
BD, guardará los cambios y mostrará una vista de confirmación, si se produce un error, mostrar la vista de
error.

Cree una nueva vista llamada Eliminado:

27
Img. 11. Crear vista llamada "Eliminado", para utilizar como confirmación.
Agregue el mensaje correspondiente a la nueva vista:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Programa Educativo Eliminado
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>El programa educativo ha sido eliminado.</h2>


<%: Html.ActionLink("Volver a la lista de programas educativos",
"Index") %>

</asp:Content>
Modifiquemos ahora los enlaces en la lista de programas educativos para que el link “Delete” apunte a la
nueva acción Eliminar.

<%: Html.ActionLink(“Delete”, “Delete”, new { id=item.IdPE })%>

quedaría como

<%: Html.ActionLink(“Eliminar”, “Eliminar”, new { id=item.IdPE })%>

28
Elimine el link <%: Html.ActionLink(“Details”, “Details”, new { id=item.IdPE })%> ya que no lo
implementaremos.
Implementar una acción Detalles implica mostrar todos los detalles correspondientes para cada PE como
datos estadísticos: cuatrimestres, alumnos en total, grupos, etc.

Terminada nuestra acción Eliminar y los links correspondientes, ahora comprobemos que ya puede
eliminar.

Img. 12. Lista de PE's con el link Eliminar.

Img. 13. Confirmar la eliminación.

29
Img. 14. Notificación del registro eliminado.

Img. 15. Lista de PE´s después de eliminar el registro.


Después de implementar estas acciones y verificar que funcionen, aquí termina esta parte, en la siguiente
entrega iremos agregando cuatrimestres a los PE´s.

Aplicación web con ASP.NET


MVC 2 – parte 5

30
Img. 1. Resultado final de este avance.
Continuando con el desarrollo de nuestra aplicación ASP.NET MVC 2, seguiremos trabajando con el
AdministrarPEController donde agregaremos un poco más de funcionalidad, para ello se plantea lo
siguiente:
El Index de AdministrarPEController muestra la lista de PE’s, donde ahora queremos que al dar clic en
un PE (por ahora no tienen link) nos lleve a ver sus cuatrimestres considerando solo mostrar los
cuatrimestres del año actual; por ejemplo: estamos en el 2011, cuando entremos a ver los cuatrimestres,
solo nos muestre los del 2011, si aún no se han creado, nos permita hacerlo pero evitar que se creen
cuatrimestres duplicados (son solo 3 por año y cada uno tiene definido su periodo), además nos permita
ver el historial de cuatrimestres del PE, por ejemplo ver la lista de cuatrimestres del año pasado y así
poder ingresar al historial (más adelante será el historial de grupos).
Si se hacen pelotas, imaginen como podríamos saber cuantos grupos tiene el PE TIC-SI (TSU) en el
cuatrimestre septiembre-diciembre del 2011, cuantos tuvo en el cuatrimestre mayo-agosto 2011, y
cuantos tuvo en el cuatrimestre enero-abril2011, para saberlo hay que revisar el historian ¿No?, y
si quisiéramos saber ¿cuantos tuvo en los cuatrimestres del año 2010?, solo debemos imaginarlo y pensar
en como le daríamos solución.

Entonces a trabajar, de aquí en adelante solo iré agregando las partes del código y una breve explicación,
puesto que ya se familiarizaron con el controlador, las acciones, las vistas, los ActionLink, las consultas
LINQ y expresiones LAMBDA.

A partir de aquí empezaremos a utilizar CSS y JQuery para realizar consultas AJAX junto con JSON, así
que si también no estamos familiarizados (por lo menos tener la idea de que se esta haciendo o de que se
trata) entonces es necesario consultar http://jquery.com/ y http://www.json.org/
La acción ProgramaEducativo.

31
Será la encargada de mostrar los cuatrimestres del año actual de cada PE, permitirá agregar nuevos
cuatrimestres y eliminar cuatrimestres siempre y cuando no tengan ningún grupo asociado, la vista
permitirá visualizar la lista de cuatrimestres de años anteriores.

// GET: /AdministrarPE/ProgramaEducativo
public ActionResult ProgramaEducativo(int id)
{
//buscar primero el programa educativo

var programaeducativo = BD.ProgramaEducativo.Where(p => p.IdPE == id).FirstOrDefault();

//si existe el PE, cargar sus cuatrimestres


if (programaeducativo != null)
{
//buscar los cuatrimestres del año actual para el ID del PE seleccionado
var cuatrimestresPE = BD.Cuatrimestre.Where(c => c.IdPE == id && c.Anio == DateTime.Now.Year);

//pasar a la vista el ID del PE y el nombre del PE por medio de ViewData


//ya que solo admite un objeto o colección de objetos (los datos llamados Modelo)
ViewData["IdPE"] = programaeducativo.IdPE;
ViewData["NombrePE"] = programaeducativo.Nombre;

//pasar la lista de cuatrimestres a la vista, si no hay ningúno, la lista aparecerá vacia.


return View(cuatrimestresPE.ToList());
}
else //si no existe, devolver la vista Error.
return View("Error");
}
Creemos la vista tipada para la clase Cuatrimestre con contenido List.

32
Img. 2. Crear vista tipada para mostrar la lista de cuatrimestres del PE.
Modifiquemos parte del código de la vista para mostrar los textos deseados, la tabla de cuatrimestres solo
debe mostrar el Id del cuatrimestre, un campo Periodo (conformado por Inicio, Fin y Año), eliminaremos
el link de Edit y Details.

Al parecer el campo Nombre sale sobrando, así que ve al diseño de la tabla, puedes eliminarlo de la tabla
y actualizar el modelo (recuerda hacerlo también en la BD vacía que tenemos de respaldo para que junto
con al de prueba sean iguales).

Esta vista también ya contiene el form para crear un nuevo cuatrimestre (estará oculto) donde los textbox
son de solo lectura, en tiempo de ejecución los llenaremos con JavaScript, incluye también la tabla del
historial (también aparcererá oculta).

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Cuatrimestres del Programa Educativo
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">


<script src="../../Scripts/jquery-1.4.1.js" type="text/javascript">
</script>
<script src="../../Content/Scripts/cuatrimestres.js"
type="text/javascript"></script>

<h2>Programa Educativo: <%: ViewData["NombrePE"] %></h2>

33
<h4>Cuatrimestres del año <%: DateTime.Now.Year %></h4>

<% //Mostrar el form para crear un nuevo cuatrimestre


(deberá aparecer oculto) %>
<p>
<a href="#" id="crearnuevocuatrimestre">Crear nuevo cuatrimestre</a>.
</p>
<div id="crearcuatrimestre" class="oculto">
<fieldset>
<legend>Crear cuatrimestre</legend>
<form id="datoscuatrimestre"
action="/AdministrarPE/NuevoCuatrimestre/<%:
ViewData["IdPE"] %>" method="post">
<input type="radio" value="1" id="cuatrimestre1"
name="ncuatrimestre"/><label>Enero - Abril</label><br />
<input type="radio" value="2" id="cuatrimestre2"
name="ncuatrimestre"/><label>Mayo - Agosto</label><br />
<input type="radio" value="3" id="cuatrimestre3"
name="ncuatrimestre"/><label>Septiembre - Diciembre</label><br />

<div class="editor-label">
<label for="PeriodoInicio">Inicio</label>
</div>
<div class="editor-field">
<input id="PeriodoInicio" name="PeriodoInicio" type="text"
value="" readonly="readonly"/>
</div>
<div class="editor-label">
<label for="PeriodoFin">Fin</label>
</div>
<div class="editor-field">
<input id="PeriodoFin" name="PeriodoFin" type="text"
value="" readonly="readonly"/>
</div>
<div class="editor-label">
<label for="Anio">Año</label>
</div>
<div class="editor-field">
<input id="Anio" name="Anio" type="text" value="<%:
DateTime.Now.Year %>" readonly="readonly"/>
</div>
<input type="hidden" id="IdPE" name="IdPE" value="<%:
ViewData["IdPE"] %>" />
<p>
<input type="submit" id="EnviarForm"
value="Registrar cuatrimestre" /> |
<a href="#" id="cancelarcrearcuatrimestre">Cancelar</a>.
</p>
<div id="mensaje"></div>
</form>
</fieldset>
</div>
<% //FIN Mostrar el form para crear un nuevo cuatrimestre. %>

<% //Tabla de cuatrimestres del PE, aparece visible %>


<table>
<tr>
<th></th>
<th>
Id
</th>

34
<th>
Periodo
</th>
<th>
Año
</th>
</tr>

<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink("Eliminar", "Delete", new { id=item.Id })%>
</td>
<td>
<%: item.Id %>
</td>
<td>
<%: item.PeriodoInicio + " - " + item.PeriodoFin %>
</td>
<td>
<%: item.Anio %>
</td>
</tr>

<% } %>
</table>
<% //FIN Tabla de cuatrimestres del PE. %>

<% //Aquí irá el historial de cuatrimestres, deberá aparecer oculto %>


<p>
<a href="#" id="mostrarh">Historial del programa educativo</a>
</p>
<div id="historial" class="oculto">
<table id="historialtbl">
<tr>
<th>
Id
</th>
<th>
Periodo
</th>
<th>
Año
</th>
</tr>
</table>
</div>

</asp:Content>
Ejecutando nuestra app, y accediendo nuestra nueva
acciónhttp://localhost:2958/AdministrarPE/programaeducativo/1 tenemos el resultado:

35
Img. 3. Vista previa de la vista ProgramaEducativo/N
Creemos nuestro CSS
Abre tu editor de textos favorito, guarda tu nuevo archivo como misestilos.css en la carpeta Content de tu
proyecto (busca tu carpeta de proyecto en el explorador de windows), el contenido del archivo es:
.oculto{
display:none;
}
Ahora incluyamos nuestro archivo en la plantilla, ve a Views/Shared/ y abre Site.Master, y agrega la linea
correspondiente para que se incluya tu nuevo css.

<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />


<link href="../../Content/misestilos.css" rel="stylesheet" type="text/css" />
Ve al navegador y actualiza la página, veremos que nuestros elementos ocultos yá estan ocultos :D

36
Img. 4. Elementos ocultos en la vista.
Creemos nuestros JavaScripts
Ahora utilizaremos JQuery, las aplicaciones ASP.NET MVC 2 ya incluyen la versión 1.4.1, actualmente
está disponible la versión 1.6.4, puedes descargarla y actualizar tus JS.
Bien, entonces en tu editor de textos creemos un nuevo archivo y lo guardaremos en la carpeta
Content/Scripts de nuestra aplicación, el archivo le llamaremos cuatrimestres.js ya que si la guardamos
en la carpeta Scripts de la app donde estan los jquery y otros js no nos permitirá utilizar nuestro propio js.
En el explorador de soluciones mostremos los archivos ocultos e incluyamos en el proyecto el
archivo misestilos.css y la carpeta Scripts.
Donde agregaremos todo lo necesario para mostrar los elementos ocultos, crear el nuevo cuatrimestre y
cargar el historial de cuatrimestres del PE.

Entonces el contenido del nuevo archivo de javascript es:

//nueva funcion para resetear elementos de un form


jQuery.fn.reset = function () {
$(this).each (function() { this.reset(); });
}

//Al hacer clic sobre el link "Crear nuevo cuatrimestre"


//mostrar form
$("#crearnuevocuatrimestre").live("click", function(event){

//recuperar la lista de cuatrimestres existentes


//desactivar los radiobutton de los cuatrimestres ya existentes
var url ="/AdministrarPE/CuatrimestresDelPE/"+$("#IdPE").val();
//hacer la llamada JSON
$.getJSON(url,
function(data) {

37
$.each(data, function(i, item) {
//verificar cuales cuatrimestres ya existen
//si existen deshabilitar el radiobutton
correspondiente
if(data.c1== true)
$("#cuatrimestre1").attr("disabled","disabled");
if(data.c2== true)
$("#cuatrimestre2").attr("disabled","disabled");
if(data.c3== true)
$("#cuatrimestre3").attr("disabled","disabled");
});
});

$("#crearcuatrimestre").show("slow");
//event.preventDefault();
//ocultar el link
$("#crearnuevocuatrimestre").hide();
});

//Al hacer clic sobre el Cancelar para "Crear nuevo cuatrimestre"


//resetear y ocultar el form
$("#cancelarcrearcuatrimestre").live("click", function(event){
//resetear el form
$("#datoscuatrimestre").reset();
$("#mensaje").html("");
$("#crearcuatrimestre").hide("slow");
//mostrar el link
$("#crearnuevocuatrimestre").show();
});

//al hacer clic sobre un radiobutton, llenar


//los txt del cuatrimestre con los datos correspondientes
$("#cuatrimestre1").live("click", function(event){
$("#PeriodoInicio").val("Enero");
$("#PeriodoFin").val("Abril");
});
$("#cuatrimestre2").live("click", function(event){
$("#PeriodoInicio").val("Mayo");
$("#PeriodoFin").val("Agosto");
});
$("#cuatrimestre3").live("click", function(event){
$("#PeriodoInicio").val("Septiembre");
$("#PeriodoFin").val("Diciembre");
});

//al hacer clic en el botón Registrar cuatrimestre


$("#EnviarForm").live("click", function(event){
event.preventDefault();
$("#mensaje").html("");

if($("#PeriodoInicio").val() == "" || $("#PeriodoFin").val() == "")


{
$("#mensaje").html("No se puede crear el cuatrimestre,
seleccione el cuatrimestre a crear.<br>Si el cuatrimestre a crear est&aacute;
deshabilitado, es porque ya existe.");
return;
}else
$("#datoscuatrimestre").submit();
});
La acción que responde con JSON

38
En el JS al hacer clic sobre el link “Crear nuevo cuatrimestre”, primero obtiene la lista de cuatrimestres
actuales, de los cuales si alguno ya existe, deshabilita el radiobutton correspondiente para evitar que
vuelva a crearse el mismo cuatrimestre.

Para esto hace una llamada AJAX que como resultado obtiene un conjunto de datos con formato JSON
los cuales son el resultado de invocar a una acción en el controlador, la acción es la siguiente:

//Respuesta a la acción invocada por AJAX-JSON


//La acción devuelve un resultado JSON
//que es la lista de cuatrimestres ya registrados para el PE
[ActionName("CuatrimestresDelPE")]
public JsonResult CuatrimestresDelPE(int id)
{
//buscar los cuatrimestres del año actual para el PE
var cuatrimestresPE = BD.Cuatrimestre.Where(c => c.IdPE == id
&& c.Anio == DateTime.Now.Year);

//variables auxiliares para almacenar nuestros cuatrimestres


bool c1= false;
bool c2 = false;
bool c3 = false;

//recorrer la lista
foreach(Cuatrimestre cuatrimestre in cuatrimestresPE)
{
if(cuatrimestre.PeriodoInicio.Trim() == "Enero" &&
cuatrimestre.PeriodoFin.Trim() == "Abril")
c1=true;
if(cuatrimestre.PeriodoInicio.Trim() == "Mayo" &&
cuatrimestre.PeriodoFin.Trim() == "Agosto")
c2=true;
if(cuatrimestre.PeriodoInicio.Trim() == "Septiembre" &&
cuatrimestre.PeriodoFin.Trim() == "Diciembre")
c3=true;
}

//Creamos el resultado JSON


//donde indicamos los cuatrimestres y si estos existen
return this.Json(new { c1 = c1, c2 = c2, c3 = c3},
JsonRequestBehavior.AllowGet);
}
La acción que registrará el Cuatrimestre.
[HttpPost]
public ActionResult NuevoCuatrimestre(Cuatrimestre cuatrimestre)
{
BD.AddToCuatrimestre(cuatrimestre);
BD.SaveChanges();

//agregado el registro (objeto), redireccionar los


cuatrimestres del PE.
return Redirect("../ProgramaEducativo/"+cuatrimestre.IdPE);
}
Antes de comprobar que funcione nuestra app, probaremos con agregar algunos Cuatrimestres como
historial en nuestra tabla.

39
Img. 5. Registrar algunos datos históricos.
Comprobando funcionalidad
Ya con los datos, ahora comprobemos que nuestra app puede agregar nuevos cuatrimestres.

Img. 6. Intentando crear registro sin seleccionar cuatrimestre (no lo permite).

40
Img. 7. Registrar el cuatrimestre seleccionado.

41
Img. 8. Cuatrimestre creado, verificando que no permita volver a crearlo.
Y bien, hasta aquí ya funciona nuestra app, pero aún falta la parte del historial.

Agregue los link en la vista Index para que al hacer clic sobre el nombre de un PE lo dirija hacia sus
cuatrimestres (el trabajo realizado).

Aplicación web con ASP.NET


MVC 2 – parte 6
Continuando con el controlador AdministrarPE implementaremos la parte de mostrar el historial de
cuatrimestres para el PE seleccionado.

La acción HistorialPE (JsonResult)


Se encargará de devolver la lista de cuatrimestres de los años anteriores al actual en un tipo de datos
JSON, la cual será invocada con JQuery al hacer clic sobre el link “Mostrar historial”.

42
Dada la situación de que la lista de cuatrimestres proveniente de nuestra base de datos no la podemos
transformar a JSON, debemos crearnos una clase auxiliar llamada AuxCuatrimestre, esta clase debemos
crearla en la carpeta Models, el código para esta clase es:

namespace EscuelaWebApp.Models
{
public class AuxCuatrimestre
{
private int id;
private string periodo;
private int anio;

public int Id
{
get { return id; }
set { id = value; }
}

public string Periodo


{
get { return periodo; }
set { periodo = value; }
}

public int Anio


{
get { return anio; }
set { anio = value; }
}

}
}
Ahora, el código de nuestra acción HistorialPE que devuelve JSON es:

[ActionName("HistorialPE")]
public JsonResult HistorialPE(int id)
{
var cuatrimestres = BD.Cuatrimestre.Where(c => c.IdPE == id
&& c.Anio < DateTime.Now.Year).ToList();
List<AuxCuatrimestre> historial = new List<AuxCuatrimestre>();

foreach (Cuatrimestre cuatrimestre in cuatrimestres)


historial.Add(
new AuxCuatrimestre {
Id = cuatrimestre.Id,
Periodo = cuatrimestre.PeriodoInicio.Trim() + " - "
+ cuatrimestre.PeriodoFin.Trim(),
Anio = cuatrimestre.Anio
});

return this.Json(historial, JsonRequestBehavior.AllowGet);


}
Editar el archivo cuatrimestres.js
Complementemos el JS para que al hacer clic en Mostrar historial, realice la consulta JSON y cargue en
tiempo de ejecución los cuatrimestres en la tabla correspondiente.

Entonces a nuestro JS le agregamos:

43
//Cuando de clic sobre MostrarHistorial
var historialcargado=false;
$("#mostrarh").live("click", function(event){

//comprobar ya se ha cargado el historial


if(historialcargado==false)
{
//cargar el historial con JSON
var url ="/AdministrarPE/HistorialPE/"+$("#IdPE").val();
//hacer la llamada JSON
$.getJSON(url,
function(data) {
$.each(data, function(i, item) {
//agregar los datos a la tabla
"historialtbl"
var fila=
"<tr><td>"+item.Id+"</td>"+item.Periodo+"</td>"+"<td>"+item.Anio+"</td></tristorialtbl").append(fila);
});
historialcargado=true;
});
}

//mostrar el historial
$("#historial").slideToggle("slow");

});
Verifiquemos que funcione.

44
Img. 1. Mostrando el historial.
Mostrar el historial ahora esta funcionando, continuemos ahora con la parte de eliminar cuatrimestres.

Eliminar cuatrimestres.
Creemos la acción correspondiente.

// GET: /AdministrarPE/EliminarCuatrimestre
public ActionResult EliminarCuatrimestre(int id)
{
//buscar el cuatrimestre
var cuatrimestre = BD.Cuatrimestre.Where(c =>
c.Id == id).FirstOrDefault();

//si el cuatrimestre existe


if (cuatrimestre != null)
{
//comprobar que el cuatrimestre no tenga ningún grupo creado
if (cuatrimestre.Grupo.Count == 0)
{
//pasar el cuatrimestre a la vista para eliminarlo
return View(cuatrimestre);
}
else
{
//si tiene grupos, mostrar una notificación con otra vista
return View("ErrorEliminar");
}
}
else
return View("Error"); //si no existe
}
Antes de crear la vista correspondiente, modifiquemos la vista ProgramaEducativo para que el link
eliminar nos lleve a la acción EliminarCuatrimestre:

actualmente el link se crea con <%: Html.ActionLink(“Eliminar”, “Delete”, new { id=item.Id })%>
modificado quedaría:

<%
//solo si el cuatrimestre no tiene ningún grupo, mostrar el link
if(item.Grupo.Count == 0)
{
%>
<%: Html.ActionLink("Eliminar", "EliminarCuatrimestre",
new { id = item.Id }) %>
<%
}
%>
Ahora sí, creemos la vista EliminarCuatrimestre:

45
Img. 2. Crear la vista EliminarCuatrimestre.
Modifiquemos el código de la vista:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Eliminar Cuatrimestre
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Eliminar Cuatrimestre</h2>

<h3>¿Está seguro de eliminar el cuatrimestre?</h3>


<fieldset>
<legend>Datos</legend>

<div class="display-label"><strong>Id</strong>:</div>
<div class="display-field"><%: Model.Id %></div>

<div class="display-label"><strong>Programa educativo</strong>:</div>


<div class="display-field"><%: Model.ProgramaEducativo.Nombre %></div>

<div class="display-label"><strong>Inicio de periodo</strong>:</div>


<div class="display-field"><%: Model.PeriodoInicio %></div>

<div class="display-label"><strong>Fin de periodo</strong>:</div>


<div class="display-field"><%: Model.PeriodoFin %></div>

<div class="display-label"><strong>Año</strong>:</div>

46
<div class="display-field"><%: Model.Anio %></div>

</fieldset>
<% using (Html.BeginForm()) { %>
<p>
<input type="submit" value="Eliminar" /> |
<%: Html.ActionLink("Cancelar", "ProgramaEducativo",
new { id = Model.IdPE })%>
</p>
<% } %>

</asp:Content>
En el caso que el cuatrimestre a eliminar ya tiene grupos, no puede eliminarse, para notificarlo al usuario
lo haremos con otra vista, así que creemos una nueva vista llamada ErrorEliminar, la vista es tipada de
la clase Cuatrimestre con contenido Empty.

Img. 3. Crear la vista ErrorEliminar.


El código para nuestra vista será:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Eliminar cuatrimestre.
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>No se puede eliminar el cuatrimestre.</h2>

<p><b>El cuatrimestre que está intentando eliminar actualmente tiene

47
grupos asignados.</b></p>
<fieldset>
<legend>Datos del cuatrimestre</legend>

<div class="display-label"><strong>Id</strong>:</div>
<div class="display-field"><%: Model.Id %></div>

<div class="display-label"><strong>Programa educativo</strong>:</div>


<div class="display-field"><%: Model.ProgramaEducativo.Nombre %></div>

<div class="display-label"><strong>Grupos asociados</strong>:</div>


<div class="display-field"><%: Model.Grupo.Count %></div>

<div class="display-label"><strong>Inicio de periodo</strong>:</div>


<div class="display-field"><%: Model.PeriodoInicio %></div>

<div class="display-label"><strong>Fin de periodo</strong>:</div>


<div class="display-field"><%: Model.PeriodoFin %></div>

<div class="display-label"><strong>Año</strong>:</div>
<div class="display-field"><%: Model.Anio %></div>

</fieldset>

<%: Html.ActionLink("OK, yá entendí", "ProgramaEducativo",


new { id = Model.IdPE })%>

</asp:Content>
Confirmar la eliminación.
Como en el ejemplo de eliminar PE, ahora creemos la acción de confirmación para eliminar el
cuatrimestre.

[HttpPost]
public ActionResult EliminarCuatrimestre(int id, string confirmar)
{
//buscar el objeto en la BD
var cuatrimestre = BD.Cuatrimestre.Where(c => c.Id == id).FirstOrDefault();

//si el registro existe, eliminarlo


if (cuatrimestre != null)
{
ViewData["IdPE"] = cuatrimestre.IdPE;
BD.DeleteObject(cuatrimestre);
BD.SaveChanges();
return View("CuatrimestreEliminado");
}
else
return View("Error");
}
Creemos la vista CuatrimestreEliminado.

48
Img. 4. Crear vista CuatrimestreEliminado.
Su código:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Cuatrimestre Eliminado
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>El cuatrimestre ha sido eliminado.</h2>


<%: Html.ActionLink("Volver al programa educativo", "ProgramaEducativo",
new { id = ViewData["IdPE"] }) %>

</asp:Content>
Comprobando funcionalidad.
Ejecutando nuestra aplicación, ingresemos a los cuatrimestres del PE de prueba.

49
Img. 5. Intentar eliminar un cuatrimestre.
Si fuera el caso que el cuatrimestre tiene grupos asignados nos mostrará:

50
Img. 6. Cuando un cuatrimestre tiene grupos.
Pero cuando un cuatrimestre no tiene grupos:

Img. 7. Confirmar la eliminación del cuatrimestre.

Img. 8. Cuatrimestre eliminado.


Regresando al PE:

51
Img. 9. Cuatrimestres del PE.
Bien, pues hasta aquí terminamos la parte de los cuatrimestres, continuaremos con la gestión de grupos
para cada cuatrimestre.

Aplicación web con ASP.NET


MVC 2 – parte 7
El avance que hasta ahora tenemos es que podemos ver nuestros PE, agregarles cuatrimestres y ver el
historial de cuatrimestres.

Lo que haremos ahora será implementar un controlador que nos permita administrar los registros de
tutores y poder filtrarlos por PE.

El resultado final a obtener en esta parte 7 es:

52
Img. 1. Resultado a obtener al finalizar esta parte.
Como ya estamos familiarizados con la parte de crear vistas tipadas, iremos avanzando un poco más
rápido, solo que a nuestra vista principal le agregaremos un ComboBox más para realizar los filtros.
Agregaremos también una clase personalizada para usarla en nuestra vista que muestre la lista.

Creemos el controlador AdministrarTutores:

Img. 2. Crear el nuevo controlador.


Agreguemos la ActionResult llamada Index(), que reciba un parámetro del tipo int inicializado en cero
“0”, ¿Porqué?, porque en el caso de invocar a AdministrarTutores que nos muestre la lista de todos los
tutores registrados (sin filtro), pero cuando invoquemos a AdministrarTutores?idpe=N especificando el
parámetro y su valor significa que estamos indicando que nos muestre los tutores del PE indicado.

Entonces nuestro controlador irá quedando como:

public class AdministrarTutoresController : Controller

53
{
BDEscolarEntities BD = new BDEscolarEntities();

//
// GET: /AdministrarTutores/
public ActionResult Index(int idpe=0)
{
if (idpe == 0)
{
ViewData["NombrePE"] = "Todos los programas educativos";
var tutores = BD.Tutor.ToList();
return View(tutores);
}
else
{
ProgramaEducativo pe = BD.ProgramaEducativo.Where(p => p.IdPE == idpe).FirstOrDefault();
if (pe != null)
{
ViewData["NombrePE"] = pe.Nombre;
var tutores = BD.Tutor.Where(p => p.ProgramaEducativo.IdPE == pe.IdPE).ToList();
return View(tutores);
}
else
return View("Error");
}
}
}
Crear la vista Index (para mostrar una lista de tutores):

54
Img. 3. Crear vista para mostrar la lista de tutores.
Hagamos algunas modificaciones a la vista como: título, mostrar nombre del programa educativo
mostrado, mostrar el programa educativo de cada tutor, modificar el link para registrar un nuevo tutor,
etc.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Administrar Tutores
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Tutores del programa educativo: <%: ViewData["NombrePE"] %></h2>

<table>
<tr>
<th></th>
<th>
Id
</th>
<th>
Nombre
</th>
<th>
Apellidos
</th>
<th>
Programa Educativo
</th>
</tr>

<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink("Edit", "Edit", new { id=item.IdTutor }) %> |
<%: Html.ActionLink("Details", "Details", new { id=item.IdTutor })%> |
<%: Html.ActionLink("Delete", "Delete", new { id=item.IdTutor })%>
</td>
<td>
<%: item.IdTutor %>
</td>
<td>
<%: item.Nombre %>
</td>
<td>
<%: item.Apellidos %>
</td>
<td>
<%: item.ProgramaEducativo.NombreCorto%>
</td>
</tr>

<% } %>

</table>

<p>
<%: Html.ActionLink("Registrar nuevo tutor", "Registrar") %>

55
</p>

</asp:Content>
Como tenemos ya algunos PE registrados, agreguemos ahora 2 registros a la tabla tutores.

Img. 4. Agregar tutores manualmente.


Recuerde que como nuestra tabla Tutor esta relacionada
porTutor.IdPE aProgramaEducativo.IdPE debemos especificar un valor de clave primaria válido
para nuestro campoTutor.IdPE, como en nuestro ejemplo el PE con IdPE=1 es TIC-SI y el PE con
IdPE=2 es Admon, estamos agregando un tutor para cada uno de los programas educativos.
Agregados nuestros registros, ejecutemos nuestra aplicación para ver nuestro resultado.

Img. 5. Lista de todos los tutores.


Especificando el parámetro para filtrar por programa educativo.

56
Img. 6. Tutores filtrados por Id del programa educativo.
Registrar nuevos tutores.
En la vista correspondiente al mostrar el formulario para registrar el nuevo tutor, debemos mostrar la lista
de programas educativos para seleccionar al que forma parte el nuevo tutor.

La acción Registrar.
//
// GET: /AdministrarTutores/Registrar
public ActionResult Registrar()
{
//Preparar lista de los programas educativos
var programaseduc = BD.ProgramaEducativo.ToList();
//Pasar la lista de pe's a la vista
ViewData["ProgramasEducativos"] = programaseduc;
//crear un nuevo objeto de la clase tutor
//para poder asociarlo con el combo a mostrar en el formulario
Tutor nuevotutor = new Tutor();
//pasar el objeto nuevotutor a la vista
return View(nuevotutor);
}
Crear la vista.

57
Img. 7. Crear la vista Registrar.
Modificado el código de la vista para que muestre el combo de programas educativos queda de esta
forma:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Registrar nuevo tutor
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Registrar nuevo tutor.</h2>

<% using (Html.BeginForm()) {%>


<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>Datos del tutor</legend>

<% // eliminamos el div donde se muestra el txt para IdTutor %>

<div class="editor-label">
<%: Html.LabelFor(model => model.Nombre) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Nombre) %>
<%: Html.ValidationMessageFor(model => model.Nombre) %>
</div>

58
<div class="editor-label">
<%: Html.LabelFor(model => model.Apellidos) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Apellidos) %>
<%: Html.ValidationMessageFor(model => model.Apellidos) %>
</div>

<div class="editor-label">
<%// eliminar Html.LabelFor(model => model.IdPE) %>
Programa Educativo.
</div>
<div class="editor-field">
<% // reemplazar Html.TextBoxFor(model => model.IdPE) por el Html.DropDownList %>
<% // Esto nos crea un combobox mostrando el nombre corto del pe como texto
// y el IdPE como name y value del combo.
// y esta sociado a la propiedad IdPE del tutor.
%>
<%: Html.DropDownList("IdPE", new SelectList(ViewData["ProgramasEducativos"] as IEnumerable,
"IdPE", "NombreCorto", Model.IdPE))%>
<%: Html.ValidationMessageFor(model => model.IdPE) %>
</div>

<p>
<br />
<input type="submit" value="Guardar" />
</p>
</fieldset>

<% } %>

<div>
<%: Html.ActionLink("Regresar a la lista de tutores", "Index") %>
</div>

</asp:Content>
Ahora verificando la funcionalidad obtenemos:

59
Img. 8. Registrar nuevo tutor mostrando la lista de programas educativos.
Registrar el nuevo tutor.
Nuestra acción [HttpPost] Registrar se encargará de guardar el nuevo objeto en la BD y redireccionarnos
a la lista de tutores del programa educativo al que pertenece el nuevo tutor.

// GET: /AdministrarTutores/Registrar
[HttpPost]
public ActionResult Registrar(Tutor tutor)
{
//Agregar el nuevo tutor
BD.AddToTutor(tutor);
//guardar los cambios en la bd
BD.SaveChanges();

//redireccionar a la lista de tutores del PE


return Redirect("Index?idpe="+tutor.IdPE);
}
Probando que nuestra app pueda registrar y redireccionar:

60
Img. 9. Registrando un nuevo tutor.

Img. 10. El tutor ha sido registrado y se ha redireccionado a la lista de tutores del PE.

61
Ahora por su propia cuenta cree las acciones correspondientes para Editar y Eliminar tutores, apóyese en
el controlador AdministrarPE donde se realizó la implementación similar, pero en esta ocasión también
debe mostrar el mismo formulario que se muestra en la vista Registrar, considere también que al intentar
eliminar el tutor debe comprobarse que no esté asignado a algún grupo.

El resultado que debe obtener será como se muestra en la imagen (modificar los links de la vista Index).

Img. 11. La vista Index con links para editar, eliminar y ver la lista completa de tutores.

62
Img. 12. Editando los datos del tutor.

Img. 13. Tutor modificado.

63
Img. 14. Eliminando un tutor.
Entonces la tarea es implementar las acciones comentadas, ahora que si después de intentarlo nadamás no
se puede, pues agreguen un comentario para pasarles los fragmentos de código en los que tienen
problemas.

Aplicación web con ASP.NET


MVC 2 – parte 8
Validación de formularios
En esta parte del tutorial nos centraremos en realizar las validaciones de los datos en nuestros formularios,
de forma que haremos solo un ejemplo y por su parte implementará las validaciones en el resto de los
formularios.

Trabajaremos en la modificación de las vistas para Registrar y Editar (ProgramaEducativo) del


controlador AdministrarPE donde nuestro resultado será el siguiente:

64
Img. 1. Validación de formularios.
Plantillas compartidas.
Como nos dimos cuenta al crear vistas para Registrar y Editar es que ambas vistas incluyen los mismos
campos en el formulario, excepto por IdPE para Editar; esto es lo mismo con cualquier otras vistas para
crear y editar registros.

Una de las formas de evitar crear 2 vistas para un mismo fin es crear plantillas compartidas
llamadasEditor Template.

Img. 2. Carpeta de plantillas usadas por todos los controladores.


En la carpeta Views tenemos otra carpeta llamada Shared donde se almacenarán todas las vistas y
plantillas compartidas que podrán ser utilizadas por todos los controladores, para crear nuestros Editor
Templates compartidos, debemos agregar una nueva carpeta llama EditorTemplates como se ve en la
imagen 2.
.

65
Img. 3. Carpeta para plantillas.
Si se requiere crear plantillas que serán utilizadas en un solo controlador, entonces en la carpeta
Views/[NombreControlador] debe crearse una carpeta llamada EditorTemplates, en este ejemplo
crearemos esta carpeta en Views/AdministrarPE como se ve en la imagen 3.
.

Crear la plantilla ProgramaEducativo.


Crearemos la plantilla a utilizar para Registrar y Editar un programa educativo, esta será creada
en Views/AdministrarPE/EditorTemplates.

Para ello, sobre esta carpeta, con botón derecho seleccionamos Agregar/ Vista.

La vista a crear será un poco diferente a las vistas Registrar y Editar, ya que se está pensando que esta
vista será incluida dentro de las vistas Registrar y Editar, este tipo de plantillas se le define como vista
parcial y debe llevar el mismo nombre de la clase correspondiente, en este caso, la clase es
ProgramaEducativo.
Ya en la ventana para crear vista.

66
Img. 4. Crear vista parcial ProgramaEducativo.
Solo asegúrese de seleccionar Crear una vista parcial, en content seleccione Create o Edit.

Agregada la vista, le haremos modificaciones al código de forma que solo quede la parte para los campos
Nombre y NombreCorto.

<div class="editor-label">
<%: Html.LabelFor(model => model.Nombre) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Nombre) %>
<%: Html.ValidationMessageFor(model => model.Nombre) %>
</div>

<div class="editor-label">
Nombre corto
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.NombreCorto) %>
<%: Html.ValidationMessageFor(model => model.NombreCorto) %>
</div>
Modificar la vista Registrar y Editar.
Abra el código de la vista Registrar.aspx y elimine la parte del código que muestra los elementos del
formulario (Nombre y NombreCorto), ya que ahora se encuentran en la plantilla, la parte del código
modificado en la vista Registrar quedaría algo como:
<fieldset>

67
<legend>Datos del programa educativo</legend>

<%: Html.EditorFor(model => Model) %>

<p>
<input type="submit" value="Registrar programa educativo" />
</p>
</fieldset>
Nota: El código resaltado en negrita fue el que reemplazo al código que ahora tenemos en nuestra
plantilla ProgramaEducativo.ascx
Ejecutemos nuestra app y vayamos a intentar registrar un nuevo programa educativo.

Img. 5. Formulario utilizando vista parcial.


Ahora haga lo mismo con la parte de código correspondiente en la vista Editar.aspx, la parte modificada
quedará de esta forma.
<fieldset>
<legend>Datos del programa educativo</legend>

<%: Html.EditorFor(model => Model) %>

<p>
<input type="submit" value="Guardar Cambios" />
</p>
</fieldset>
La validación de datos del formulario.
ASP.NET MVC tiene la ventaja de ofrecernos herramientas y uso fácil para realizar esta tarea, el
procedimiento es el siguiente:
1. Crear una clase que se encargue de la validación de datos (clase parcial de metadatos).
2. Configurar la validación con MicrosoftAjax en nuestro formulario.
3. Verificar su funcionamiento.

68
Actualmente nuestros formularios tienen un fallo muy importante que debemos considerar, estos no
realizan ninguna validación de los datos que son ingresados en sus campos, las validaciones que debemos
considerar son los tipos de datos correctos, ya que de no recibir los datos correctos colapsará la base de
datos y de paso la aplicación.

Es fácil agregar la validación a nuestra aplicación mediante la adición de anotaciones de datos para las
clases de nuestro modelo. Las anotaciones de datos nos permiten describir las reglas que se desean aplicar
a las propiedades de nuestro modelo (clases), y ASP.NET MVC se hará cargo de hacerlas cumplir y la
visualización de los mensajes adecuados a los usuarios.
Para una clase simple del modelo, agregando una anotación de datos es manejada por la instrucción
using paraSystem.ComponentModel.DataAnnotation, y a continuación, colocar los atributos ensus
propiedades, de esta forma:
using System.ComponentModel.DataAnnotations;
namespace Validacion.Models
{
public class Persona
{
[Required]
public string Nombre { get; set; }

[Required]
public string Apellidos { get; set; }

public int Edad { get; set; }


}
}
El ejemplo anterior ([Required]) hace que los valores para Nombre y Apellidos sean campos obligatorios
en nuestros formularios.
Utilización de clases parciales de metadatos con Entity Framework (MetaData Partial Classes
withData Annotations) para validar datos.
Cuando queremos validar los datos al crear un objeto (registro) de alguna clase de nuestro modelo,
debemos implementar una clase parcial de la misma (mismo nombre) para no sobrescribir la ya existente
en el modelo.

Nuestro ejemplo se basa en validar los datos al registrar un nuevo programa educativo, así que en nuestra
carpeta Models, agregaremos una nueva clase con el mismo nombre de “ProgramaEducativo”.

En el contenido de nuestra clase declararemos nuestra clase metadata.

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace EscuelaWebApp.Models
{
[MetadataType(typeof(ProgramaEducativoMetaData))]
public partial class ProgramaEducativo
{
//Reglas de validación para la clase ProgramaEducativo

public class ProgramaEducativoMetaData


{
//Las reglas van aquí

69
}
}
}
Agregando validaciones (Data Annotations) a nuestro formulario ProgramaEducativo.
La clase parcial ProgramaEducativo tiene un atributo llamado MetadataType que apunta a la clase
ProgramaEducativoMetaData, en esta última declararemos las reglas de validación a las cuales
agregaremos algunos atributos como las anotaciones:

 Required – Indica que la propiedad es un campo obligatorio.


 DisplayName – Define el texto que desea utilizar en los campos del formulario y los mensajes
de validación.
 StringLength – Define una longitud máxima de un campo de tipo cadena.
 Range – Establece un valor máximo y mínimo para el valor de un campo numérico.
 Bind – Listas de campos para excluir o incluir en los valores de enlace de parámetros o la
forma para modelar las propiedades.
 ScaffoldColumn – Permite ocultar campos de los formularios editor.
Para obtener más información acerca de Data Annotations, visite el link http://msdn.microsoft.com/es-
mx/library/system.componentmodel.dataannotations.aspx
Revisa también este tutorial http://www.asp.net/mvc/tutorials/validation-with-the-data-annotation-
validators-cs (
no digas “hay no, está en inglés”).
Entonces el código completo para nuestra clase parcial ProgramaEducativo queda como:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace EscuelaWebApp.Models
{
[MetadataType(typeof(ProgramaEducativoMetaData))]
public partial class ProgramaEducativo
{
//Reglas de validación para la clase ProgramaEducativo

[Bind(Exclude = "IdPE")] //Excluir IdPE de la validación


public class ProgramaEducativoMetaData
{
//Reglas

//El campo IdPE lo configuramos para Scaffold dejando la gestión de su valor al sql server.
//el campo ya ha sido excluido en nuestro formulario - plantilla (ProgramaEducativo.ascx)
[ScaffoldColumn(false)]
public object IdPE { get; set; }

[Required(ErrorMessage = "El nombre es obligatorio.")]


public object Nombre { get; set; }

[Required(ErrorMessage = "El nombre corto es obligatorio.")]


[DisplayName("Nombre corto")] //Mostrar "Nombre corto" en lugar de NombreCorto.
[StringLength(12,ErrorMessage = "El nombre corto debe tener como máximo 12 caracteres.")]
public object NombreCorto { get; set; }
}
}
}

70
Habilitar la validación con AJAX (Validación por el lado del cliente).
Solo falta modificar nuestra plantilla o formulario ProgramaEducativo.ascx para que pueda realizar la
validación de datos con AJAX, entonces vamos al código de ProgramaEducativo.ascx donde agregamos.
<%@ Import Namespace="EscuelaWebApp" %>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EscuelaWebApp.Models.ProgramaEducativo>" %>

<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>


<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
Nota: La línea de código tachado es como referencia para saber donde deben agregarse las lineas de
código faltantes, más no debe eliminarse.
Los archivos JS deben existir en nuestra carpeta Scripts, sino existen por alguna casualidad, cree otro
nuevo proyecto de ASP.NET MVC 2 y copie los scripts desde el nuevo proyecto.
Ahora debemos utilizar el método Html.EnableClientValidation helper para habilitar o activar la
validación en nuestros formularios, para esto debemos volver a modificar las vistas Registrar y Editar.
Actualmente nuestras vistas en la parte del formulario tienen:

<% using (Html.BeginForm()) {%>


<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>...
Donde la línea resaltada en negrita debe eliminarse, y agregar una nueva linea antes del inicio del
formulario, al final esta parte del código queda:

<% Html.EnableClientValidation(); %>


<% using (Html.BeginForm()) {%>

<fieldset>
<legend>Datos del programa educativo</legend>
La línea resaltada en negrita es la nueva linea agregada para activar la validación.

Ahora comprobemos la validación, para ello ejecute la aplicación y vaya a registrar un nuevo programa
educativo, sin ingresar ningún datos, haga clic en el botón para crearlo, deben saltar nuestros mensajes de
error especificados en nuestra clase parcial ProgramaEducativo.

71
Img. 6. Probando validación de datos.

Img. 7. Validando formularios.

72
Img. 8. Validando datos de formularios.
Y bien, la validación ha funcionado al ingresar solo algunos valores e ingresando una longitud excedida
para un campo.

Su labor ahora es implementar la validación para las vistas Registrar y Editar para la clase Tutor
(Controlador AdministrarTutores) y para el resto de las vistas Editar y Registrar que se irán creando debe
ir implementando la validación.

73
Img. 9. Validar datos en Registrar y Editar Tutor.

Aplicación web con ASP.NET


MVC 2 – parte 9
En esta parte de nuestro tutorial, implementaremos la administración de grupos para nuestros
cuatrimestres en un nuevo controlador llamado AdministrarGrupos, en esta parte haremos uso de JQuery
para visualizar nuestros registros de grupos por cuatrimestres y programa educativo, posteriormente
implementaremos también la gestión de alumnos.

74
Img. 1. Resultado de nuestro avance al finalizar esta parte.
El nuevo controlador AdministrarGrupos.
Agregue el nuevo controlador AdministrarGrupos, cuya acción Index puede recibir un parámetro que será
el Id del cuatrimestre del cual se quieren visualizar sus grupos, sin recibir parámetro mostrará solo la
vista vacía (sin ninguna lista), pero ademas debe mostrar controles para alternar la información que
queremos visualizar; algo similar ya se ha hecho en la acción Index de AdministrarTutores (revise esa
parte para entender de que se trata y como funciona).

Img. 2. Agregar nuevo controlador AdministrarGrupos.


El código de nuestro controlador empezará con nuestra acción Index (Requiere de más trabajo, debe
analizar el código fuente para entender su funcionamiento):

public class AdministrarGruposController : Controller


{
BDEscolarEntities BD = new BDEscolarEntities();
//
// GET: /AdministrarGrupos/

75
public ActionResult Index(int idcuatrimestre=0)
{
//Crear la lista de programas educativos para mostrarlos en la vista Index
var programaseducativos = BD.ProgramaEducativo.ToList();
programaseducativos.Insert(0, new ProgramaEducativo { IdPE = 0, NombreCorto = "" });

//Pasar la lista de PE´s a la vista


ViewData["ProgramasEducativos"] = programaseducativos;

//Crear parámetros auxiliares para


//Id del programa educativo (si se está recibiendo el id de cuatrimestre)
//Id del cuatrimestre (si se está recibiendo el id de cuatrimestre)
//Nombre del PE (si se está pasando el id de cuatrimestre)
//Periodo del cuatrimestre
ViewData["IdPE"] = "";
ViewData["IdCuatrimestre"] = "";
ViewData["ProgramaEducativo"] = "";
ViewData["Cuatrimestre"] = " - ";
//si no se está especificando el cuatrimestre
//crear una lista vacia de la clase Grupo
if (idcuatrimestre == 0)
{
//Crear la lista vacía porque no se mostrar grupos de algún cuatrimestre
List<Grupo> grupos = new List<Grupo>();

//pasar la lista vacía a la vista


return View(grupos);
}
else //Si se especifica el cuatrimestre, cargar sus grupos
{
//Buscar el cuatrimestre indicado
//como restricción, debe ser del año actual
var cuatrimestre = BD.Cuatrimestre.Where(c => c.Id == idcuatrimestre && c.Anio ==
DateTime.Now.Year).FirstOrDefault();
if (cuatrimestre != null)
{
//Pasar los datos reales
ViewData["IdPE"] = cuatrimestre.IdPE;
ViewData["ProgramaEducativo"] = cuatrimestre.ProgramaEducativo.NombreCorto.Trim();
ViewData["IdCuatrimestre"] = cuatrimestre.Id;
ViewData["Cuatrimestre"] = cuatrimestre.PeriodoInicio.Trim() + " - " + cuatrimestre.PeriodoFin.Trim();

//Pasar la lista de cuatrimestres al que corresponde el indicado


//utilizando nuestra clase auxiliar
List<AuxCuatrimestre> cuatrimestres = new List<AuxCuatrimestre>();

//Recorrer la lista de cuatrimestres (ordenados a-z) del PE


foreach(Cuatrimestre item in cuatrimestre.ProgramaEducativo.Cuatrimestre.Where(c => c.IdPE ==
cuatrimestre.IdPE && c.Anio== DateTime.Now.Year).OrderBy(c => c.PeriodoInicio))
cuatrimestres.Add( new AuxCuatrimestre { Id = item.Id, Periodo = item.PeriodoInicio.Trim() + " - " +
item.PeriodoFin.Trim(), Anio = item.Anio});

//Ahora si pasamos nuestra lista de cuatrimestres


ViewData["cuatrimestres"] = cuatrimestres;

//Y el dato principal es la lista de grupos del cuatrimestre seleccionado


return View(cuatrimestre.Grupo.ToList());
}
else
return View("Error");
}

76
}

}
La vista Index.
Crear la vista tipada para la clase Grupo con contenido List.

Img. 3. Crear vista Index.


El código de nuestra vista Index, empieza como a continuación se muestra, posteriormente se le irán
haciendo modificaciones donde se les mostrarán las lineas de código como guías para saber donde hacer
los cambios.

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Administrar grupos
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Administrar grupos</h2>
Filtrar por Programa Educativo: <%: Html.DropDownList("IdPE", new SelectList(ViewData["ProgramasEducativos"]
as IEnumerable, "IdPE", "NombreCorto", ViewData["IdPE"]))%>
Cuatrimestre:

<% // si se tiene la lista de cuatrimestres, crear el combo con sus opciones, sino, crear uno vacío %>
<% if (ViewData["cuatrimestres"] != null)
{ %>

77
<%: Html.DropDownList("IdCuatrimestre", new SelectList(ViewData["cuatrimestres"] as IEnumerable, "Id",
"Periodo", ViewData["IdCuatrimestre"]))%>
<%}
else
{ %>
<select id="IdCuatrimestre" name="IdCuatrimestre"></select>
<% } %>
<br /><br />

<strong>Programa Educativo</strong>: <span id="nombrepe"><%: ViewData["ProgramaEducativo"] %></span>,


<strong>Cuatrimestre</strong>: <span id="nombrecuatrimestre"><%: ViewData["Cuatrimestre"] %></span>.<br
/><br />

<% // asignamos un ID para nuestra tabla de grupos


// porque la manipularemos con JQuery %>

<table id="GruposTbl">
<% //Cambia de TR a THEAD la fila del encabezado de la tabla %>
<thead>
<th></th>
<th>
Id Grupo
</th>
<th>
Nombre
</th>
<th>
Cuatrimestre
</th>
<th>
Tutor
</th>
</thead>
<% //Agrega la etiqueta TBODY a la tabla
//Lo utilizaremos para manipular su contenido %>
<tbody>
<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink("Editar", "Editar", new { id=item.IdGrupo }) %> |
<%: Html.ActionLink("Eliminar", "Eliminar", new { id=item.IdGrupo })%>
</td>
<td>
<%: item.IdGrupo %>
</td>
<td>
<%: item.Nombre %>
</td>
<td>
<% //Cambia el IdCuatrimestre por el periodo del cuatrimestre %>
<%: item.Cuatrimestre.PeriodoInicio + " " + item.Cuatrimestre.PeriodoFin %>
</td>
<td>
<% //Cambia el IdTutor por el nombre completo del tutor %>
<%: item.Tutor.Nombre + " " + item.Tutor.Apellidos%>
</td>
</tr>

<% } %>
</tbody>

78
</table>

<p id="LinkAltaGrupo">
<%: Html.ActionLink("Create New", "Create") %>
</p>

</asp:Content>
Comprobando la funcionalidad:
Al ejecutar nuestra aplicación y al ingresar a http://localhost:XXXX/AdministrarGrupos nos mostrará
nuestra vista como se ve en la imagen.

Img. 4. Vista sin especificar el Id del cuatrimestre.


Observe que no se está pasando el Id del cuatrimestre del cual se quieren ver sus grupos, razón por la cual
la lista aparece vacía (pero tampoco se han creado grupos :D), Aparece la lista de PE, y el combo de
cuatrimestres aparece vacío, cuando el usuario seleccione un PE, se llenará automáticamente el combo de
cuatrimestres.

Ahora ingresemos a la vista pero especificando el parámetro idcuatrimestre cuyo valor sea un Id de
cuatrimestre válido, cheque sus PE´s registrados y vea los ID de alguno de sus cuatrimestres, en mi caso
mis ID de cuatrimestres válidos (año 2011) son los ID 9 y 10, así que probaré con uno de ellos.

79
Img. 5. Vista que recibe el id del cuatrimestre.
Hasta aquí va funcionando correctamente, pero hace falta algo muy importante, el registro de nuevos
grupos.

Lo que haremos será, si se ha especificado un Id de cuatrimestre para ver sus grupos, mostraremos el link
Registrar grupo, por ahora el link lo tenemos como “Create New“.
Así que en la vista Index, reemplace la linea de código (dentro del párrafo con id=”LinkAltaGrupo”):

<%: Html.ActionLink(“Create New”, “Create”) %>

por:

<% if (ViewData["IdCuatrimestre"] != "")


{ %>

<%: Html.ActionLink("Registrar nuevo grupo", "Registrar", new { id = ViewData["IdCuatrimestre"] })%>

<% } %>
Ahora verifique que al ingresar en http://localhost:XXXX/AdministrarGrupos no muestre el link, y al
especificar el id de cuatrimestre si muestre el link,
ej. http://localhost:XXXX/AdministrarGrupos?idcuatrimestre=9.
Registrar Grupos.
Crearemos la acción Registrar y su vista en la cual el usuario solo tenga que seleccionar los valores
(nombre o letra del grupo y Tutor).

La acción Registrar.
public ActionResult Registrar(int id)
{
//Verificar que el cuatrimestre para el que se ha de registrar el grupo existe

var cuatrimestre = BD.Cuatrimestre.Where(c => c.Id == id).FirstOrDefault();


if (cuatrimestre != null)
{
//crear un nuevo objeto de la clase Grupo y definir sus datos que tendrá por defecto

80
Grupo nuevogrupo = new Grupo();

//asociar el objeto cuatrimestre al grupo


nuevogrupo.Cuatrimestre = cuatrimestre;

List<AuxTutor> tutores = new List<AuxTutor>(); //crear una lista con la nueva clase auxiliar

//transformar nuestra lista de tutores a nuestra nueva lista de la clase AuxTutor


//En esta clase solo asignamos el ID y el nombre completo del tutor
foreach (Tutor tutor in BD.Tutor.Where(t => t.IdPE == cuatrimestre.IdPE))
tutores.Add(new AuxTutor { Id = tutor.IdTutor, Nombre = tutor.Nombre.Trim() + " " + tutor.Apellidos.Trim() });

//Pasar a la vista la lista de tutores del PE al que pertenece el cuatrimestre


ViewData["Tutores"] = tutores;

//pasar nuestro objeto a la vista


return View(nuevogrupo);
}else
return View("Error");
}
Observe que en esta acción estamos utilizando otra nueva clase llama AuxTutor en la cual solo le
implementamos 2 propiedades, para ello, en la carpeta Models, agregue esta clase:
namespace EscuelaWebApp.Models
{
public class AuxTutor
{
private int id;
private string nombre;

public int Id
{
get { return id; }
set { id = value; }
}

public string Nombre


{
get { return nombre; }
set { nombre = value; }
}

}
}
Crear la vista Registrar:

81
Img. 6. Crear la vista Registrar.
En esta vista utilizaremos una nueva vista parcial (plantilla) para no trabajar doble en las vistas
Registrar y Editar, el código de nuestra vista Registrar quedará así:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Registrar grupo
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Registrar grupo</h2>

<% using (Html.BeginForm()) {%>


<%: Html.ValidationSummary(true) %>

<fieldset>
<legend>Datos del grupo</legend>
<p><%:ViewData["Mensaje"] %></p>
<%: Html.EditorFor(model => Model, ViewData["Tutores"] = ViewData["Tutores"]) %>

<p>
<input type="submit" value="Registrar grupo" />
</p>
</fieldset>

<% } %>

<div>

82
<%: Html.ActionLink("Regresar a la lista de grupos", "Index", new { idcuatrimestre = Model.Cuatrimestre.Id },
null)%>
</div>

</asp:Content>
Crear nuestra vista parcial llamada Grupo.ascx
En la carpeta Views/AdministrarGrupos agregue su carpeta EditorTemplates, de la misma forma
como se explicó en la parte 8 cuando empezamos a trabajar con la validación de formularios.
Ahora a EditorTemplates agregue una nueva vista parcial llamada Grupo:

Img. 7. Crear vista parcial Grupo.


El código para nuestra vista parcial quedará como este:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<EscuelaWebApp.Models.Grupo>" %>

<div class="editor-label">
Programa educativo
</div>
<div class="editor-field">
<% // crear un cuadro de texto donde se muestre el nombre del programa educativo como solo lectura %>
<input type="text" value="<%: Model.Cuatrimestre.ProgramaEducativo.NombreCorto %>" readonly="readonly"
/>
</div>

<div class="editor-label">
Cuatrimestre
</div>
<div class="editor-field">
<% // crear nuestro campo IdCuatrimestre

83
// como input Hiden que porte el Id del cuatrimestre (no se puede modificar)
// y aparte un cuadro de texto donde se muestre el periodo del cuatrimestre como solo lectura %>
<%: Html.HiddenFor(model => model.IdCuatrimestre)%>
<input type="text" value="<%: Model.Cuatrimestre.PeriodoInicio + " - " + Model.Cuatrimestre.PeriodoFin %>"
readonly="readonly" />
</div>

<div class="editor-label">
Nombre del grupo
</div>
<div class="editor-field">
<% //: Html.TextBoxFor(model => model.Nombre) %>
<% // Crear un combo para seleccionar la letra del grupo %>
<select id="Nombre" name="Nombre">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
<option value="D">D</option>
<option value="E">E</option>
<option value="F">F</option>
</select>
<%: Html.ValidationMessageFor(model => model.Nombre) %>
</div>

<div class="editor-label">
Tutor
</div>
<div class="editor-field">
<% //: Html.TextBoxFor(model => model.IdTutor) %>
<%: Html.DropDownList("IdTutor", new SelectList(ViewData["Tutores"] as IEnumerable, "Id", "Nombre"))%>
<%: Html.ValidationMessageFor(model => model.IdTutor) %>
</div>
Puede implementar un mecanismo para gestionar las letras para asignar como nombre del grupo, de forma
que pudiera comprobar cuales nombres ya existen y no mostrarlos a usuario para que no pueda
seleccionarlo como opción.

Ahora comprobemos la funcionalidad, para ello ingrese a ver los grupos de un cuatrimestre,
ej.http://localhost:XXXX/AdministrarGrupos?idcuatrimestre=9:
Vemos que tenemos nuestro link para agregar un nuevo grupo a este cuatrimestre.

84
Img. 8. Ir a registrar nuevo grupo.
Ahora al hacer clic sobre “Registrar nuevo grupo“, tenemos nuestro resultado:

Img. 9. Vista registrar grupo.


Falta crear nuestra acción Registrar que reciba los datos del formulario y los guarde en la BD.

La acción [HttpPost] Registrar queda como:


[HttpPost]
public ActionResult Registrar(Grupo grupo)

85
{
//primero comprobaremos que el nombre del grupo no exista
//para el cuatrimestre seleccionado.
var comprobargrupo = BD.Grupo.Where(g => g.Nombre.Trim() == grupo.Nombre && g.IdCuatrimestre ==
grupo.IdCuatrimestre).FirstOrDefault();
//si el grupo NO existe, agregarlo a la BD.
if (comprobargrupo == null)
{
BD.AddToGrupo(grupo);
BD.SaveChanges();

//Redireccionar a los grupos del cuatrimestre para el que se creó el grupo


return Redirect("..\\Index?idcuatrimestre="+grupo.IdCuatrimestre);
}
else //Si ya existe el grupo, informarlo a usuario
{
//volver a recuperar el cuatrimestre para obtener todos sus datos
var cuatrimestre = BD.Cuatrimestre.Where(c => c.Id == grupo.IdCuatrimestre).FirstOrDefault();
if (cuatrimestre != null)
grupo.Cuatrimestre = cuatrimestre; //reasigar el objeto cuatrimestre al grupo

//ViewData["Mensaje"] es recibido por la vista Registrar.


ViewData["Mensaje"] = "No se puede registrar el grupo ("+grupo.Nombre +") porque ya existe, elija otra letra a
asignar.";

//Volver a crear nuestra lista tutores


List<AuxTutor> tutores = new List<AuxTutor>();
//transformar nuestra lista de tutores a nuestra nueva clase
foreach (Tutor tutor in BD.Tutor.Where(t => t.IdPE == grupo.Cuatrimestre.ProgramaEducativo.IdPE))
tutores.Add(new AuxTutor { Id = tutor.IdTutor, Nombre = tutor.Nombre.Trim() + " " + tutor.Apellidos.Trim() });

//Pasar a la vista la lista de tutores del PE al que pertenece el cuatrimestre


ViewData["Tutores"] = tutores;

//Regresamos nuevamente el objeto grupo a la vista para su modificación


return View(grupo);
}
Ahora ejecutando nuestra aplicación al registrar nuestro nuevo grupo, tenemos nuestra acción HttpPost
Registrar funcionando.

86
Img. 10. Grupo registrado.
Ahora al intentar registrar nuevamente un grupo con la letra o nombre “A“, nos devuelve la vista con los
datos del grupo pero NO registrado.

87
Img. 11. Intentando registrar el mismo grupo.
Notese que para la clase Grupo no es están validando los datos (no se hace validación de formulario),
lo que se hace es que antes de registrar el grupo se verifica que no exista un grupo con el mismo
nombre o letra para el cuatrimestre seleccionado, si ya existe, pasamos un mensaje de error a la vista,
pero no esta de más que por su cuenta implemente la validación para esta clase y haga que los combos
aparezcan vacíos para que el usuario elija una opción.
Por su cuenta implemente la acciones Editar y Eliminar, solo considere que para eliminar un grupo
debe comprobar que no tenga asignado ningún alumno.
Esta parte del tutorial queda hasta aquí para no hacerlo más largo, en la siguiente parte agregaremos la
funcionalidad a los combos Programa educativo y Cuatrimestre para hacer las consultas AJAX y JSON
para cambiar el contenido de nuestra tabla de grupos, de esa forma el usuario no tendrá que regresar a
PE´s y seleccionar cuatrimestre para administrar sus grupos.

Aplicación web con ASP.NET


MVC 2 – parte 10
En la parte 9 de nuestro tutorial empezamos la implementación de la administración de grupos, donde
comentamos que el contenido de la tabla se modificaría al cambiar los combobox para los cuales
implementaremos el evento Change() de ambos combobox.

Todos los datos solicitados al servidor serán devueltos en formato JSON, para lo cual implementaremos
una acción en el controlador para que al solicitarle los cuatrimestres (para el PE seleccionado en el
combo.) nos devuelva el resultado y será procesado con JQuery.

Img. 1. Resultado al finalizar esta parte del tutorial.


En sí, continuaremos trabajando con el controlador AdministrarGrupos y la vista
Index.
La acción que devolverá la lista de cuatrimestres del PE seleccionado.
[ActionName("CuatrimestresPE")]
public JsonResult CuatrimestresPE(int idpe)
{
//cargar los cuatrimestres del año actual para el PE seleccionado

88
var cuatrimestres = BD.Cuatrimestre.Where(c => c.IdPE == idpe && c.Anio == DateTime.Now.Year).ToList();

//crear nuestra lista con la clase auxiliar


List<AuxCuatrimestre> listacuatrimestres = new List<AuxCuatrimestre>();

//convertir de la clase original a la auxiliar


foreach (Cuatrimestre cuatrimestre in cuatrimestres)
listacuatrimestres.Add(
new AuxCuatrimestre
{
Id = cuatrimestre.Id,
Periodo = cuatrimestre.PeriodoInicio.Trim() + " - " + cuatrimestre.PeriodoFin.Trim(),
Anio = cuatrimestre.Anio
});
//devolver el resultado JSON
return this.Json(listacuatrimestres, JsonRequestBehavior.AllowGet);
}
Para comprobar su funcionalidad, ejecute la aplicación e ingrese a la dirección de esta acción y
especifique el valor para el parámetro idpe con un valor de clave primaria válido para algún PE.
http://localhost:XXXX/AdministrarGrupos/cuatrimestrespe?idpe=1
nos devolverá como resultado algo similar a:

[{"Id":9,"Periodo":"Septiembre - Diciembre","Anio":2011},{"Id":10,"Periodo":"Enero - Abril","Anio":2011}]


Llamar a la acción y procesar el resultado con JQuery
Agregue un nuevo archivo llamado admingrupos.JS (javascript) a la
carpeta Content/Scripts como lo hizo con cuatrimestres.js
En este nuevo archivo JS implementaremos el evento Chage para el combo con el Id=IdPE que se
encuentra en nuestra vista Index.

//Al seleccionar un PE, cargar los cuatrimestres


$("#IdPE").live("change", function (event) {
//obtener el Id del PE seleccionado
var idpe = $("#IdPE").val();

//limpiar el combo
$("#IdCuatrimestre").children("option").remove();

//Si el ID del PE seleccionado es diferente de 0, cargar sus cuatrimestres


if(idpe > 0) {

//cargar los cuatrimestres con JSON


var url ="/AdministrarGrupos/CuatrimestresPE?idpe="+idpe;

//hacer la llamada JSON


$.getJSON(url,
function (data) {
var opcion = "<option value=\"0\"></option>";
$("#IdCuatrimestre").append(opcion);
$.each(data, function(i, item) {
//agregar los cuatrimestres al combo IdCuatrimestre"
var opcion= "<option
value=\""+item.Id+"\">"+item.Periodo+"</optione").append(opcion);
});
});
}
});

89
//Al seleccionar el cuatrimestre, cargar sus grupos
//...
Ahora agregue el archivo JS de JQuery y admingrupos.js a la vista Index como se hizo anteriormente
en un caso similar.
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script src=”../../Scripts/jquery-1.4.1.js” type=”text/javascript”></script>
<script src=”../../Content/Scripts/admingrupos.js” type=”text/javascript”></script>
Nota: Recuerde que la línea tachada es solo de referencia.
Ahora ingrese a la vista Index de AdministrarGrupos y seleccione el PE para comprobar que el combo de
cuatrimestres cambie sus opciones.

Img. 2. Probando la funcionalidad del combo de PE's.


Al seleccionar un PE.

Img. 3. Al seleccionar un combo, se cargan los cuatrimestres en el otro combo.

90
Ahora al seleccionar un cuatrimestres, deben cargarse sus grupos, para ello, agregaremos nuestra acción
al controlador.

Pero como una lista de alguna entidad de nuestro modelo no puede serializarse porque contiene
propiedades de navegación, debemos crear una nueva clase auxiliar.

Agregue una nueva clase llamada AuxGrupo a Models, implemente la nueva clase.
public class AuxGrupo
{
private int id;
private string nombre;
private string cuatrimestre;
private string tutor;

public int Id
{
get { return id; }
set { id = value; }
}

public string Nombre


{
get { return nombre; }
set { nombre = value; }
}

public string Cuatrimestre


{
get { return cuatrimestre; }
set { cuatrimestre = value; }
}

public string Tutor


{
get { return tutor; }
set { tutor = value; }
}

//implemente más miembros de esta clase si fueran necesarios


}
Ahora la acción GruposCuatrimestre en nuestro controlador.

[ActionName("GruposCuatrimestre")]
public JsonResult GruposCuatrimestre(int idcuatrimestre)
{
//cargar los grupos del cuatrimestre seleccionado
var grupos = BD.Grupo.Where(g => g.IdCuatrimestre == idcuatrimestre).ToList();

//crear nuestra lista con la clase auxiliar AuxGrupo


List<AuxGrupo> listagrupos = new List<AuxGrupo>();

//convertir de la clase original a la auxiliar de Grupo


foreach (Grupo grupo in grupos)
{
listagrupos.Add(
new AuxGrupo
{
Id = grupo.IdGrupo,

91
Nombre = grupo.Nombre.Trim(),
Cuatrimestre = grupo.Cuatrimestre.PeriodoInicio.Trim() + " - " + grupo.Cuatrimestre.PeriodoFin.Trim() + " - " +
grupo.Cuatrimestre.Anio,
Tutor = grupo.Tutor.Nombre.Trim() + " " + grupo.Tutor.Apellidos.Trim()
});
}

return this.Json(listagrupos, JsonRequestBehavior.AllowGet);


}
Igualmente para comprobar que la acción funcione, ingrese a la dirección de la acción, ejemplo:

http://localhost:XXXX/AdministrarGrupos/gruposcuatrimestre?idcuatrimestre=9
El resultado devuelto puede ser algo como:

[{"Id":1,"Nombre":"A","Cuatrimestre":"Septiembre - Diciembre - 2011","Tutor":"Juan Vicente Pérez


López"}]
Complementar nuestro admingrupos.JS
Ahora implementemos el evento Change del combo con el id=IdPE, para que al seleccionar un
cuatrimestre se carguen sus grupos a la tabla.

//Al seleccionar el cuatrimestre, cargar sus grupos


$("#IdCuatrimestre").live("change", function (event) {
//obtener el Id del cuatrimestre seleccionado
var idcuatrimestre = $("#IdCuatrimestre").val();

//eliminar todas las filas de la tabla


$("#GruposTbl").find('tbody').children("tr").remove();

if (idcuatrimestre > 0) {
//mostrar el nombre de PE y el cuatrimestre
$("#nombrepe").html($("#IdPE option:selected").html());
$("#nombrecuatrimestre").html($("#IdCuatrimestre option:selected").html());

//cargar los grupos del cuatrimestre con JSON


var url = "/AdministrarGrupos/GruposCuatrimestre?idcuatrimestre=" + idcuatrimestre;

//hacer la llamada JSON


$.getJSON(url,
function (data) {
$.each(data, function (i, item) {
//agregar los grupos a la tabla
var fila = "<tr><td><a href=\"/AdministrarGrupos/Editar/" + item.Id + "\">Editar</a>
| <a href=\"/AdministrarGrupos/Eliminar/" + item.Id + "\">Eliminar</a></td><td>" + item.Id + "</td>"
+ "<td>" + item.Nombre + "</td>" + "<td>" + item.Cuatrimestre + "</td><td>" + item.Tutor +
"</td></tr>";
$("#GruposTbl").append(fila);
});
});

//habilitar el link para registrar un nuevo cuatrimestre

$("#LinkAltaGrupo").html("<a href=\"/AdministrarGrupos/Registrar/"+idcuatrimestre+"\">Registrar nuevo


grupo</a>");
}
});
Ahora ejecute la aplicación e ingrese en AdministrarGrupos, seleccione un PE y un cuatrimestre.

92
Img. 4. Comprobando la funcionalidad.
Seleccione un cuatrimestre que tenga ya registrados algunos grupos.

Img. 5. Cargando los grupos del cuatrimestre seleccionado.


Hasta aquí termina esta parte de administrar grupos, pero aún falta la administración de alumnos.

Aplicación web con ASP.NET


MVC 2 – parte 11
Después de un tiempo sin avanzar en el tutorial, hoy continuamos con la parte de gestionar los alumnos
de los grupos, donde al estar en los grupos de un determinado cuatrimestre podamos acceder a las listas
de alumnos.

93
Img. 1. Resultado final al terminar esta parte del tutorial.
Agregaremos un nuevo controlador llamado AdministrarAlumnos cuya acciónn Index muestre las listas
cargadas dinámicamente al seleccionar opciones en los combobox, pero antes, agregue el link en
cada registros de la tabla en la vista Index de AdministrarGrupos para acceder al
nuevo controlador.

Img. 2. Agregar link para acceder a los grupos de alumnos.


La instrucción para crear el link es:

<%: Html.ActionLink(“Lista de alumnos”, “Index”, “AdministrarAlumnos”, new {


idgrupo=item.IdGrupo }, null) %>
Crear controlado AdministrarAlumnos:

94
Img. 3. Controlador AdministrarAlumnos.
El código lo iremos agregando poco a poco:

namespace EscuelaWebApp.Controllers
{
public class AdministrarAlumnosController : Controller
{
BDEscolarEntities BD = new BDEscolarEntities();
//
// GET: /AdministrarAlumnos/

public ActionResult Index(int idgrupo=0)


{
//...

return View();
}

}
}
La acción Index:
Como en la acción Indes de AdministrarGrupos, esta nueva acción también recibe un parámetro
(idgrupo), del cual mostraremos sus alumnos solo si el grupo pertenece al último cuatrimestre, caso
contrario, mostraremos un mensaje de error, y si no se recibe un valor para este parámetro, mostraremos
la vista vacía.
El código de la acción queda como:

public ActionResult Index(int idgrupo=0)


{
//Consideremos que solos se pueden modificar las listas de alumno para el
//último cuatrimestre registrado

//Crear la lista de programas educativos para mostrarlos en la vista Index


var programaseducativos = BD.ProgramaEducativo.ToList();
programaseducativos.Insert(0, new ProgramaEducativo { IdPE = 0, NombreCorto = "" });
//Pasar la lista de PE´s a la vista
ViewData["ProgramasEducativos"] = programaseducativos;

//Crear parámetros auxiliares para


//Id del programa educativo (si se está recibiendo el id de grupo)
//Id del grupo

95
//Lista de grupos
//Nombre del PE
//Periodo del cuatrimestre
//Nombre o letra del grupo
ViewData["IdPE"] = "";
ViewData["Grupos"] = "";
ViewData["IdGrupo"] = "";
ViewData["ProgramaEducativo"] = "";
ViewData["Cuatrimestre"] = " - ";
ViewData["Grupo"] = "";
ViewData["Tutor"] = "";

if (idgrupo == 0)
{
//Crear la lista vacía porque no se mostrará ningún alumno.
List<Alumno> alumnos = new List<Alumno>();
return View(alumnos);
}
else
{
//si se esta recibiendo el id del grupo a mostrar
var grupo = BD.Grupo.Where(g => g.IdGrupo == idgrupo && g.Cuatrimestre.Anio == DateTime.Now.Year)
.FirstOrDefault();

//si existe el grupo


if (grupo != null)
{

//recuperar el ultimo cuatrimestre del mismo PE que el grupo para verificar que el grupo corresponde a este
//Septiembre - Diciembre
//Mayo - Agosto
//Enero - Abril
//podemos ordenarlos descendentemente por PeriodoInicio y sacar el primero de la lista :D

var cuatrimestre = BD.Cuatrimestre.Where(c => c.IdPE == grupo.Cuatrimestre.IdPE && c.Anio ==


DateTime.Now.Year).OrderByDescending(g => g.PeriodoInicio).FirstOrDefault();

//si el grupo pertenece al último cuatrimestre podremos ver su lista de alumnos


if (grupo.IdCuatrimestre == cuatrimestre.Id)
{

//cargar la lista de alumnos del grupo


var alumnos = grupo.Alumno.ToList();

//Pasar los datos reales


ViewData["IdPE"] = grupo.Cuatrimestre.IdPE;
ViewData["Grupos"] = cuatrimestre.Grupo.OrderBy(g => g.Nombre).ToList();
ViewData["IdGrupo"] = grupo.IdGrupo;
ViewData["ProgramaEducativo"] = grupo.Cuatrimestre.ProgramaEducativo.NombreCorto.Trim();
ViewData["Cuatrimestre"] = grupo.Cuatrimestre.PeriodoInicio.Trim() + " - " + grupo.Cuatrimestre.PeriodoFin.Trim()
+ " : " + cuatrimestre.Anio;
ViewData["Grupo"] = grupo.Nombre;
ViewData["Tutor"] = grupo.Tutor.Nombre.Trim() + " " + grupo.Tutor.Apellidos.Trim();
return View(alumnos);
}
else
{
//si el grupo no es del último cuatrimestre, lo informaremos al usuario.
ViewData["MensajeError"] = "No se puede modificar la lista de alumnos para el grupo seleccionado. " +
" Solo puede modificarse la lista de alumnos del último cuatrimestre, utilice esta vista.";

96
//Crear la lista vacía porque no se mostrará ningún alumno.
List<Alumno> alumnos = new List<Alumno>();
return View(alumnos);
}
}else
return View("Error");
}
}
La vista Index:
La creamos tipada para la clase Alumno con contenido List.

Img. 4. Agregar vista tipada para Alumno.


Agregaremos el código para crear nuestros combos para filtar los alumnos de determinado PE,
Cuatrimestre y Grupo.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"


Inherits="System.Web.Mvc.ViewPage<IEnumerable<EscuelaWebApp.Models.Alumno>>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">


Administrar listas de alumnos
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>


<script src="../../Content/Scripts/adminalumnos.js" type="text/javascript"></script>

97
<h2>Administrar listas de alumnos</h2>

<p id="mensaje" class="error"><%: ViewData["MensajeError"]%></p>

Filtrar por Programa Educativo: <%: Html.DropDownList("IdPE", new SelectList(ViewData["ProgramasEducativos"]


as IEnumerable, "IdPE", "NombreCorto", ViewData["IdPE"]))%>
Cuatrimestre:

<input type="text" id="Cuatrimestre" name="Cuatrimestre" size="10" readonly="readonly" value="<%:


ViewData["Cuatrimestre"]%>"/>

Grupo:

<% if (ViewData["Grupos"] != null)


{ %>
<%: Html.DropDownList("IdGrupo", new SelectList(ViewData["Grupos"] as IEnumerable, "IdGrupo", "Nombre",
ViewData["IdGrupo"]))%>
<%}
else
{ %>
<select id="IdGrupo" name="IdGrupo"><option>Seleccionar</option></select>
<% } %>
<br /><br />

<fieldset>
<legend>Datos de grupo</legend>
<strong>Programa Educativo</strong>: <span id="nombrepe"><%: ViewData["ProgramaEducativo"] %></span>,
<strong>Cuatrimestre</strong>: <span id="Cuatrimestre"><%: ViewData["Cuatrimestre"] %></span>,
<strong>Grupo</strong>: <span id="nombregrupo"><%: ViewData["Grupo"]%></span>.<br /><br />
<strong>Tutor</strong>: <span id="tutor"><%: ViewData["Tutor"]%></span>.<br /><br />

<table id="AlumnosTbl">
<% //Cambia de TR a THEAD la fila del encabezado de la tabla %>
<thead>
<th></th>
<th>
Matricula
</th>
<th>
Nombre
</th>
<th>
Apellidos
</th>
</thead>
<% //Agregar la etiqueta TBODY a la tabla
//Lo utilizaremos para manipular su contenido %>
<tbody>

<% foreach (var item in Model) { %>

<tr>
<td>
<%: Html.ActionLink("Editar", "Editar", new { id=item.Matricula }) %> |
<%: Html.ActionLink("Eliminar", "Eliminar", new { id=item.Matricula })%>
</td>
<td>
<%: item.Matricula %>
</td>
<td>

98
<%: item.Nombre %>
</td>
<td>
<%: item.Apellidos %>
</td>
</tr>

<% } %>
</tbody>
<% // Agregar el pie de la tabla para mostrar los totales %>
<tfoot>
<tr>
<th class="derecha">Total</th>
<th colspan="3"><span id="total"><%:Model.Count()
%></span>Alumnos</th>
</tr>
</tfoot>

</table>

<p id="LinkAltaAlumno">
<% if (ViewData["IdGrupo"] != "")
{ %>

<%: Html.ActionLink("Registrar nuevo alumno en este grupo.", "Registrar", new { idgrupo =


ViewData["IdGrupo"] }, null)%>

<% } %>
</p>

</asp:Content>
</fieldset>
Las acciones a devolver JSON en el controlador.
Nuestro JS llamará a las acciones en el controlador que le devolverán tanto la lista de grupos del último
cuatrimestre para el PE seleccionado como la lista de alumnos para el grupo seleccionado, para ello
recuerde que no podemos transformar una colección de Entities a JSON, por lo tanto crearemos una clase
llamada AuxAlumno, ya hemos creado anteriormente otra clase llamada AuxGrupo que también se
utilizará aquí:

La acción Grupos:
Esta acción nos devolverá la lista de grupos del último cuatrimestre para el PE seleccionado.

[ActionName("Grupos")]
public JsonResult Grupos(int idpe)
{
//cargar los grupos del ultimo cuatrimestre del PE seleccionado

//primero buscamos el ultimo cuatrimestre de PE


var cuatrimestre = BD.Cuatrimestre.Where(c => c.IdPE == idpe && c.Anio ==
DateTime.Now.Year).OrderByDescending(g => g.PeriodoInicio).FirstOrDefault();

if (cuatrimestre != null)
{
//ahora obtenemos sus grupos
var grupos = cuatrimestre.Grupo.OrderBy(g => g.Nombre).ToList();

//crear nuestra lista con la clase auxiliar AuxGrupo

99
List<AuxGrupo> listagrupos = new List<AuxGrupo>();

//convertir de la clase original a la auxiliar de Grupo


foreach (Grupo grupo in grupos)
{
listagrupos.Add(
new AuxGrupo
{
Id = grupo.IdGrupo,
Nombre = grupo.Nombre.Trim(),
Cuatrimestre = "-", //para no pasar tantos datos que no se usarán
Tutor = grupo.Tutor.Nombre.Trim() + " " + grupo.Tutor.Apellidos.Trim()
});
}

//Prepara nuestro resultado JSON para que:


//envie el periodo del cuatrimestre
//Envie la lista de sus grupos
return this.Json(
new
{
cuatrimestre = cuatrimestre.PeriodoInicio.Trim() + " - " + cuatrimestre.PeriodoFin.Trim() + " - " + cuatrimestre.Anio,
grupos = listagrupos
}, JsonRequestBehavior.AllowGet);
}else
return this.Json(new { msg = "Error al recuperar los grupos del último cuatrimestre del PE seleccionado, " +
"compruebe que el PE tiene registrados cuatrimestres y estos tienen grupos."},
JsonRequestBehavior.AllowGet);
}
Ejemplos:
Para este ejemplo: http://localhost:2958/administraralumnos/grupos?idpe=1
El usuario seleccionó el PE con el ID=1 y este es válido, la acción devolverá su último cuatrimestre del
año actual, y devolverá también la lista de sus grupos, el resultado JSON sería como:

{
"cuatrimestre":"Septiembre - Diciembre : 2011",
"grupos":[{
"Id":1,
"Nombre":"A",
"Cuatrimestre":"-",
"Tutor":"Juan Vicente Pérez López"
},
{
"Id":2,
"Nombre":"B",
"Cuatrimestre":"-",
"Tutor":"Pedro Torres"
}]
}
Otro caso sería, cuando se pasara un Id de PE no válido, ejemplo,
parahttp://localhost:2958/administraralumnos/grupos?idpe=20 el resultado será:
{"msg":"Error al recuperar los grupos del último cuatrimestre del PE seleccionado."}
La acción AlumnosGrupo:
Esta acción devolverá en resultado JSON la lista de alumnos para el PE seleccionado, para ello primero
crearemos la clase AuxAlumno de la que se comentó más arriba.

La clase AuxAlumno:
100
public class AuxAlumno
{
private int matricula;
private string apellidos;
private string nombre;

public int Matricula


{
get { return matricula; }
set { matricula = value; }
}

public string Nombre


{
get { return nombre; }
set { nombre = value; }
}

public string Apellidos


{
get { return apellidos; }
set { apellidos = value; }
}

}
Ahora sí, la acción AlumnosGrupo:
[ActionName("AlumnosGrupo")]
public JsonResult AlumnosGrupo(int idgrupo)
{
//buscar el grupo
var grupo = BD.Grupo.Where(g => g.IdGrupo == idgrupo && g.Cuatrimestre.Anio ==
DateTime.Now.Year).FirstOrDefault();
//si existe el grupo
if (grupo != null)
{

//recuperar el ultimo cuatrimestre del mismo PE que el grupo para verificar que el grupo corresponde a este
//Septiembre - Diciembre
//Mayo - Agosto
//Enero - Abril
//podemos ordenarlos descendentemente por PeriodoInicio y sacar el primero de la lista :D
var cuatrimestre = BD.Cuatrimestre.Where(c => c.IdPE == grupo.Cuatrimestre.IdPE && c.Anio ==
DateTime.Now.Year).OrderByDescending(g => g.PeriodoInicio).FirstOrDefault();

//si el grupo pertenece al último cuatrimestre podremos devolver su lista de alumnos


if (grupo.IdCuatrimestre == cuatrimestre.Id)
{
//crear nuestra lista con la clase auxiliar
List<AuxAlumno> alumnos = new List<AuxAlumno>();

//transformar de Alumno a AuxAlumno


foreach (Alumno item in grupo.Alumno.OrderBy(a => a.Apellidos).ToList())
{
alumnos.Add(
new AuxAlumno
{
Matricula = item.Matricula,
Nombre = item.Nombre.Trim(),
Apellidos = item.Apellidos.Trim()
});

101
}

//devolver el resultado JSON


return this.Json(new { tutor = grupo.Tutor.Nombre.Trim() + " " + grupo.Tutor.Apellidos.Trim(), alumnos = alumnos },
JsonRequestBehavior.AllowGet);

} return this.Json(new { msg = "Error al recuperar los alumnos del grupo seleccionado, el grupo no corresponde
al último cuatrimestre." }, JsonRequestBehavior.AllowGet);
}
else
return this.Json(new { msg = "Error al recuperar los alumnos del grupo seleccionado, no se encontró el grupo." },
JsonRequestBehavior.AllowGet);
}
Para comprobar que funciona la acción AlumnosGrupo, registraremos a mano algunos alumnos para
algunos grupos.

Img. 5. Registrar alumnos manualmente.


Nota: En esta imagen se están registrando alumnos para determinados grupos que SI Existen en mi tabla
y pertenecen al último cuatrimestre de alguno de mis PE´s registrado.
Comprobando que la acción AlumnosGrupo funciona.

Para mi grupo con el Id=1, ingreso manualmente a la


dirección http://localhost:2958/administraralumnos/alumnosgrupo?idgrupo=1 y el resultado es:
{
"tutor":"Juan Vicente Pérez López",
"alumnos":[
{"Matricula":111,"Nombre":"Benito","Apellidos":"Méndez"},
{"Matricula":112,"Nombre":"Jorge","Apellidos":"Meza"}
]
}
Por lo tanto, si ingreso a http://localhost:2958/AdministrarAlumnos?idgrupo=1 también obtendré los
datos en el resultado.

102
Img. 6. Resultado en la vista Index.
El código JavaScript.
Ahora nuevamente entra en función el uso de jQuery para recuperar los datos desde el servidor, para ello,
cree un nuevo archivo llamado adminalumnos.js en la carpeta Content/Scripts como en los casos
anteriores, agreguemos entonces el código para recuperar los datos desde el servidor y mostrarlos en la
vista.
Nuestro JavaScript queda como este:

//Al seleccionar un PE, cargar los grupos del ultimo cuatrimestre


$("#IdPE").live("change", function (event) {
//obtener el Id del PE seleccionado
var idpe = $("#IdPE").val();

//Si el ID del PE seleccionado es diferente de 0


if (idpe > 0) {

//limpiar el combo de grupos


$("#IdGrupo").children("option").remove();
$("#Cuatrimestre").val(""); //limpiar cuatrimestre
$("#mensaje").html(""); // limpiar mensaje por si tiene algo
$("#notif").html("");
//cargar los grupos del último cuatrimestre con JSON
var url = "/AdministrarAlumnos/Grupos?idpe=" + idpe;
//hacer la llamada JSON
$.getJSON(url,
function (data) {
var opcion = "<option value=\"0\"></option>";
$("#IdGrupo").append(opcion);
$("#Cuatrimestre").val(data.cuatrimestre);

if (data.msg) //si devolvió error


$("#mensaje").html(data.msg);

$.each(data.grupos, function (i, item) {


//agregar los cuatrimestres al combo IdCuatrimestre"
var opcion = "<option value=\"" + item.Id + "\">" + item.Nombre +
"</option>";
$("#IdGrupo").append(opcion);

103
});

$("#IdGrupo").focus();
$("#notif").html(" <i><strong>Seleccione el grupo.</strong></i>");
});
}
});

//Al seleccionar el Grupo, cargar sus alumnos


$("#IdGrupo").live("change", function (event) {
//obtener el Id del grupo seleccionado
var idgrupo = $("#IdGrupo").val();

//eliminar todas las filas de la tabla


$("#AlumnosTbl").find('tbody').children("tr").remove();
$("#total").html("");

if (idgrupo > 0) {
//mostrar el nombre del PE, periodo del cuatrimestre y grupo
$("#nombrepe").html($("#IdPE option:selected").html());
$("#NCuatrimestre").html($("#Cuatrimestre").val());
$("#nombregrupo").html($("#IdGrupo option:selected").html());

//cargar los alumnos del grupo con JSON


var url = "/AdministrarAlumnos/AlumnosGrupo?idgrupo=" + idgrupo;

//hacer la llamada JSON


$.getJSON(url,
function (data) {
if (data.msg) //si devolvió error
$("#mensaje").html(data.msg);

$("#tutor").html(data.tutor);
$.each(data.alumnos, function (i, item) {
//agregar los alumnos a la tabla
var fila = "<tr><td><a href=\"/AdministrarAlumnos/Editar/" + item.Matricula +
"\">Editar</a> | <a href=\"/AdministrarAlumnos/Eliminar/" + item.Matricula + "\">Eliminar</a></td><td>" +
item.Matricula + "</td>" + "<td>" + item.Nombre + "</td>" + "<td>" + item.Apellidos + "</td></tr>";
$("#AlumnosTbl").append(fila);
});

//mostrar el total de alumnos


$("#total").html(data.alumnos.length);
});

//habilitar el link para registrar un nuevo alumno en este grupo


$("#LinkAltaAlumno").html("<a href=\"/AdministrarAlumnos/Registrar?idgrupo=" + idgrupo + "\">Registrar nuevo
alumno en este grupo.</a>");
}
});
Hora de comprobar funcionalidad.
Ejecutemos nuestra App, vayamos a nuestra vista para ver las listas de alumnos.

104
Img. 7. Accediendo a nuestras listas.

Img. 8. Seleccionando un PE que no tiene cuatrimestres.

105
Img. 9. Seleccionando otro grupo en el combobox.
Hasta aquí es todo, por su parte implemente las acciones correspondientes para Registrar, Editar y si lo
prefiere, también Eliminar.

En la siguiente parte solo mostraré la generación de reportes partiendo desde estas listas de alumnos para
cada grupo.

Aplicación web con ASP.NET


MVC 2 – parte 12 – Reportes
en PDF
Ahora generaremos un reporte local en nuestra aplicación y lo presentaremos como documento PDF en el
navegador para que pueda ser impreso o guardado, para ello, utilizaremos el elemento Report Document,
y la clase LocalReport que se encuentra en el espacio de nombres Microsoft.Reporting.WebForms
(visite http://msdn.microsoft.com/es-mx/library/microsoft.reporting.webforms.localreport.aspx).
Antes de continuar, modifiquemos la vista Index y nuestro código JS para que se muestre un nuevo link
junto al link “Registrar nuevo alumno en este grupo”, el nuevo link lo apuntaremos hacia una nueva
acción que la llamaremos ImprimirLista.

106
Img. 1. Agregar link para imprimir lista.
El código a modificar en la vista Index para generar el link lo dejaremos como:

<p id="LinkAltaAlumno">
<% if (ViewData["IdGrupo"] != "")
{ %>
<%: Html.ActionLink("Registrar nuevo alumno en este grupo.", "Registrar", new { idgrupo = ViewData["IdGrupo"] },
null)%> |
<%: Html.ActionLink("Exportar como PDF", "ImprimirLista", new { idgrupo = ViewData["IdGrupo"] }, null)%>
<% } %>
</p>

Y en el JS modificado quedará como:

//habilitar el link para registrar un nuevo alumno en este grupo


$("#LinkAltaAlumno").html("<a href=\"/AdministrarAlumnos/Registrar?idgrupo=" + idgrupo + "\">Registrar nuevo
alumno en este grupo.</a>" +
"|"+
"<a href=\"/AdministrarAlumnos/ImprimirLista?idgrupo=" + idgrupo + "\">Exportar como PDF</a>");

Creando el reporte.
El reporte a crear solo consiste en llenarlo con la lista de alumnos del grupo que se este mostrando en
Index, por lo tanto, el reporte será llenado con una colección de objetos de la clase Alumno, ahora,para
poder establecer una fuente de datos (DataSource) a través de la cual se llenará el reporte, debemos
implementar un método en nuestra clase Alumno (puede ser también en una clase que en el servidor es
una vista o directamente podría llenarse a través de una función que es un procedimiento almacenado en
el servidor SQLServer).
Modificar la clase Alumno
Agregue una nueva clase Alumno en la carpeta Models (la clase será declarada como PARTIAL
CLASS, si ya implementó la validación del formulario para el registro y edición de Alumno, entonces ya
no es necesario volver a agregarla).
La partial class Alumno con nuestro nuevo método que será el DataSource de nuestro reporte quedará de
esta forma.

public partial class Alumno

107
{
/*
* Aquí pueden ir o van las reglas de validación (Clase MetaData) si es que ya implementó la validación del form
*/
//Agregamos un nuevo método estático que devuelva la lista de alumnos
//que forman parte del grupo especificado
//utilizamos la interfaz IList para nuestra colección
public static IList<Alumno> ListaAlumnos(int idgrupo)
{
BDEscolarEntities BD = new BDEscolarEntities();
//recuperar la lista de alumnos desde la BD
var alumnos = BD.Alumno.Where(a => a.IdGrupoActual == idgrupo).OrderBy(a => a.Apellidos);
return alumnos.ToList();
}
}
Agregando el reporte:
Antes de agregar el reporte, agregaremos una nueva carpeta llamada Reportes en la carpeta Content.

Img. 2. Agregar carpeta Reportes.


Ahora sobre la carpeta Reportes vamos a agregar un nuevo elemento de
tipo Informe llamadoAlumnosGrupo.

108
Img. 3. Agregar el reporte.
Ahora tendremos el diseñador de informes, entonces agregaremos el DataSource para nuestro informe,
para esto, en la ventana Datos del informe, seleccione Nuevo > Conjunto de datos.

Img. 4. Agregando nuevo conjunto de datos al informe.


Ahora especifique el nombre para el conjunto de datos, en origen de datos, seleccione el espacio de
nombres (NombreProyecto.Models), y ahora en el conjunto de datos disponibles busque la clase Alumnos
la cual ya nos muestra que disponemos de un método llamado ListaAlumnos, así que lo seleccionamos y
damos en Aceptar.

109
Img. 5. Seleccionar el conjunto de datos.
Agregamos el encabezado y pie al reporte, agregamos también la tabla en cuerpo del reporte.

Img. 6. Agregar partes al reporte.


Agreguemos parámetros al reporte, a traves de los cuales podamos especificar el nombre del PE,
cuatrimestre, grupo y nombre del tutor.

En la ventana de Datos de informe, nos ubicamos sobre Parámetros, y agregamos los parámetros
correspondientes especificando el Nombre, Tipo de dato, etc.

110
Img. 8. Agregar parámetro.
Tendremos que agregar los parámetros que comentamos.

Img. 8. Agregar los parámetros correspondientes.


Ya con los parámetros y el conjunto de datos, terminemos el diseño de nuestro reporte.

111
Img. 9. Diseño del reporte.
La acción ImprimirLista.
Esta acción que se encargará de llenar el reporte y enviarlo al navegador, comentamos que recibirá el ID
del grupo que se pretende exportar al reporte.

En esta acción utilizamos clases que se encuentran en el espacio de


nombresMicrosoft.Reporting.WebForms, por lo tanto, debemos agregar la referencia correspondiente:

Img. 10. Agregar referencia al componente Microsoft.ReportViewer.WebForms.


El código de la acción:

public ActionResult ImprimirLista(int idgrupo)


{
//comprobar que el grupo exista

112
var grupo = BD.Grupo.Where(g => g.IdGrupo == idgrupo).FirstOrDefault();
if (grupo != null)
{
//declarar el objeto de la clase LocalReport
LocalReport localReport = new LocalReport();
localReport.ReportPath = Server.MapPath("~/Content/Reportes/AlumnosGrupo.rdlc");
//Llenar los 4 parámetros que creamos en el reporte
ReportParameter[] parametros = new ReportParameter[4];
parametros[0] = new ReportParameter("ProgramaEducativo",
grupo.Cuatrimestre.ProgramaEducativo.NombreCorto.Trim());
parametros[1] = new ReportParameter("Cuatrimestre", grupo.Cuatrimestre.PeriodoInicio.Trim() + " - " +
grupo.Cuatrimestre.PeriodoFin.Trim() + " "+grupo.Cuatrimestre.Anio);
parametros[2] = new ReportParameter("Grupo", grupo.Nombre.Trim());
parametros[3] = new ReportParameter("Tutor", grupo.Tutor.Nombre.Trim() + " "+grupo.Tutor.Apellidos.Trim());
//agregar los parámetros al reporte
localReport.SetParameters(parametros);
//Preparar el DataSource del reporte
//aquí invocamos al método ListaAlumnos que agregamos a la clase Alumno
//pasandole como valor de parámetro el id del grupo que se quiere imprimir
//No hemos hablado de vistas o procedimientos almacenados, sino, aquí se invocarían directamente
ReportDataSource reportDataSource = new ReportDataSource("DatosAlumnos", Alumno.ListaAlumnos(idgrupo));
//Ahora pasamos los datos al reporte
localReport.DataSources.Add(reportDataSource);
//declaramos las variables de configuración para el reporte
string reportType = "PDF";
string mimeType;
string encoding;
string fileNameExtension;
//En la configuración del reporte debe especificarse para el tipo de reporte
//consulte el sitio para más información
//http://msdn2.microsoft.com/en-us/library/ms155397.aspx
Warning[] warnings;
string[] streams;
byte[] renderedBytes;
//Transformar el reporte a bytes para transferirlo como flujo
renderedBytes = localReport.Render(reportType, null, out mimeType,
out encoding,
out fileNameExtension,
out streams,
out warnings);
//enviar el archivo al cliente (navegador)
return File(renderedBytes, mimeType);
}
else
return View("Error");
}
Ejecutemos ahora nuestra app e intentemos ver un grupo en un reporte como PDF en nuestro navegador.

Ejemplo: quiero ver el documento para el grupo con el ID=1, 2, etc. ingreso a la
url http://localhost:2958/AdministrarAlumnos/ImprimirLista?idgrupo=1 y obtengo

113
Img. 11. Reporte generado como PDF.
Y hasta aquí terminamos nuestra implementación de reportes en nuestra aplicación de ASP.NET MVC
2.

Aplicación web con ASP.NET


MVC 2 – Estilos en
nuestras tablas
Ya que estamos trabajando con vistas con contenido List, estas nos crean tablas que pueden mostrar
varios registros y lo tedioso puede ser que al tener unos 30 registros o más tenemos que desplazar la
página para ir recorriendo la lista.

Una de las soluciones es utilizar CSS para crear un contenedor deslizable en nuestra vista y sin mover la
página podamos desplazar el contenido de la tabla.

114
Img. 1. Tabla deslizable en nuestra página con CSS.

Img. 2. Crear nuevo CSS.


Para lograr esto en la carpeta Content de nuestro proyecto (en el explorador de windows) crearemos un
nuevo archivo llamado resaltar_tabla.css (después incluimos nuestro archivo en el proyecto), ahora
antes de empezar si no estamos familiarizados con CSS, busquemos en la red algún tutorial ya que sobre
CSS hay mucha información, uno de los sitios más ricos en información acerca de css
es http://www.w3schools.com/css/
.

El contenido de nuestro archivo resaltar_tabla.css es el siguiente:


table tr:hover{
background-color:#F0F3FA;
}

#lista > table {width:99%}


#lista {
width:800px;
height: 120px;
overflow:auto;
padding-bottom:3px;
}

.derecha
{
text-align:right;
}
Donde:

 table tr:hover{ … } asignamos un color de fondo a la fila que le estemos pasando puntero del
ratón, si desea otro color, utilice algún mezclador de colores para obtener un color deseado, un
mezclador de colores en línea es http://www.colorpicker.com/.
 #lista > table {99%} en esta linea #lista es el ID de un DIV que agregaremos como contenedor
de nuestra tabla; table{99%} estamos indicando que la tabla ocupe el 99% del ancho total de
nuestro DIV.
 #lista { width: 800px; height: 120px; … } estamos asignando los estilos a nuestro DIV el cual
tendra un ancho de 800 pixeles y un alto de 120 pixeles (el resultado es la img 1), 120px se
estableció solo como prueba, debe modificar estos valores de acuerdo a sus necesidades (alto un
ancho del contenedor para mostrar la tabla.)

115
 .derecha { … } es un estilo que alinea el texto a la derecha de cualquier elemento HTML que lo
herede.
Nota: tenga en cuenta que en la img 1 se aprecia la barra de desplazamiento del DIV porque el alto es
solo de 120 px y el alto del contenido de la tabla es mayor a 120px, por lo tanto si al aumentar el alto del
DIV y el alto del contenido de la tabla en pixeles es menor que el alto del DIV, la barra de
desplazamiento no se mostrará.
Antes de utilizar nuestro CSS, nuestra vista Index de AdministrarPE se aprecia de esta forma:

Img. 3. Vista original.


Agregar el CSS a Site.Master.
Abra el código de la plantilla del sitio y agregue la línea de código correspondiente para utilizar nuestro
nuevo archivo CSS.
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
<link href="../../Content/misestilos.css" rel="stylesheet" type="text/css" />
<link href="../../Content/estilo_tabla.css" rel="stylesheet" type="text/css" />
Nota: recuerde que las lineas tachadas ya están en nuestro archivo y no deben eliminarse.
Modificar la vista Index del controlador AdministarPE:

Ahora lo que haremos a nuestra vista es agregar el DIV que comentamos y agregar el pie a nuestra tabla.

El código de nuestra vista quedará en parte como se muestra en el siguiente código, recuerde que solo
vamos a agregar lo que nos hace falta para complementar nuestras funciones, no volveremos a
implementar desde cero nuestra vista.

El código que ya tenemos está tachado y el resaltado en negrita es el que vamos a agregar.
<h2>Lista de programas educativos.</h2>

<div id="lista">
<table>
<tr>
<th></th>
<th>
Id
</th>
<th>
Nombre
</th>
<th>
Nombre corto
</th>
</tr>
<tfoot> <tr>
<th class="derecha">Total</th>
<th colspan="3"><%:Model.Count() %> Programas educativos</th>
</tr>

116
</tfoot>
... contenido de nuestra tabla (aquí va el foreach que genera las filas.) ...
</table>
</div>
Ahora ejecutemos nuestra aplicación y vayamos a AdministrarPE y tendremos el resultado:

Img. 4. Resultado final con el nuevo estilo CSS.


Observe que al pasar el ratón sobre alguna fila, esta cambia su color de fondo.

Ahora haga lo mismo que se hizo con la vista Index.aspx a las vistas que desee mostrar la tabla
deslizable en el DIV (vistas con contenido List), solo recuerde que ya no tendrá que crear más
archivos CSS y agregarlos, ya que ya se encuentra agregado en nuestro Site.Master, solo agregará el pie
a la tabla y el DIV.
Vista: Index de AdministrarTutores.

Img. 5. Lista de tutores.

117

Você também pode gostar