Mostrando las entradas con la etiqueta Helpers. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Helpers. Mostrar todas las entradas

lunes, 23 de marzo de 2015

El Demo del Día: Paginación y Ordenación Asíncrona en ASP.NET MVC con Ajax ActionLink y Vista Parcial

Paginación y Ordenación Asíncrona en ASP.NET MVC con Ajax ActionLink y Vista Parcial

Luego de casi un mes de no publicar un Demo, esta semana vamos a publicar uno diario para nivelarnos. En esta ocasión veremos como paginar y ordenar en forma asíncrona en ASP.NET MVC usando el control Helper Ajax.ActionLink y una Vista Parcial.

Requerimiento

Se desea crear una aplicación web en ASP.NET MVC que permita consultar la lista de empleados, dando la posibilidad de mostrar por páginas y ordenar los registros en forma ascendente y descendente por cada columna mostrada.
El requerimiento debe acompañarse de una buena experiencia de usuario que permita actualizar los datos al paginar u ordenar sin refrescar toda la pantalla.

Solución

Usaremos los controles Ajax.ActionLink tanto para la ordenación como la paginación, los cuales realizarán una llamada asíncrona (internamente usan jQuery Ajax) y actualizarán la vista mediante una vista parcial con los empleados.

Crear el Procedimiento Almacenado en la Base de Datos Northwind de SQL Server

Para listar los datos de los empleados crear el procedimiento "uspEmployeesListar":

Create procedure [dbo].[uspEmployeesListar]
As
Select EmployeeId,LastName,FirstName,IsNull(BirthDate,'1/1/1900') as Birthdate
From Employees

Crear una Librería de Entidades de Negocio para Northwind

Crear una librería de clases "Northwind.Librerias.EntidadesNegocio" con una clase llamada "beEmpleado" que tenga el siguiente código:

using System;
namespace Northwind.Librerias.EntidadesNegocio
{
    public class beEmpleado
    {
        public int IdEmpleado { get; set; }
        public string Apellido { get; set; }
        public string Nombre { get; set; }
        public DateTime FechaNacimiento { get; set; }
        public byte[] Foto { get; set; }
    }
}

Crear una Librería de Acceso a Datos para Northwind

Crear una librería de clases "Northwind.Librerias.AccesoDatos" con una clase llamada "daEmpleado" que tenga el siguiente código:

namespace Northwind.Librerias.AccesoDatos
{
    public class daEmpleado
    {
        public List<beEmpleado> Listar(SqlConnection con)
        {
            List<beEmpleado> lbeEmpleado = null;
            SqlCommand cmd = new SqlCommand("uspEmployeesListar", con);
            cmd.CommandType = CommandType.StoredProcedure;

            SqlDataReader drd = cmd.ExecuteReader(CommandBehavior.SingleResult);
           
            if (drd != null)
            {
                lbeEmpleado = new List<beEmpleado>();
                beEmpleado obeEmpleado;
                int posIdEmpleado = drd.GetOrdinal("EmployeeID");
                int posApellido = drd.GetOrdinal("LastName");
                int posNombre = drd.GetOrdinal("FirstName");
                int posFechaNacimiento = drd.GetOrdinal("BirthDate");
                while (drd.Read())
                {
                    obeEmpleado = new beEmpleado();
                    obeEmpleado.IdEmpleado = drd.GetInt32(posIdEmpleado);
                    obeEmpleado.Apellido = drd.GetString(posApellido);
                    obeEmpleado.Nombre = drd.GetString(posNombre);
                    obeEmpleado.FechaNacimiento = drd.GetDateTime(posFechaNacimiento);
                    lbeEmpleado.Add(obeEmpleado);
                }
                drd.Close();
            }
            return (lbeEmpleado);
        }
    }
}

Nota: Hay que referenciar a la librería de entidades de negocio anteriormente creada.

Crear una Librería de Reglas de Negocio para Northwind

Crear una librería de clases "Northwind.Librerias.AccesoDatos" con una clase llamada "daEmpleado" que tenga el siguiente código:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Configuration;
using Northwind.Librerias.EntidadesNegocio;
using Northwind.Librerias.AccesoDatos;

namespace Northwind.Librerias.ReglasNegocio
{
    public class brEmpleado
    {
        public List<beEmpleado> Listar()
        {
            List<beEmpleado> lbeEmpleado = null;
            string CadenaConexion = ConfigurationManager.
            ConnectionStrings["conNW"].ConnectionString;
            using (SqlConnection con = new SqlConnection(CadenaConexion))
            {
                try
                {
                    con.Open();
                    daEmpleado odaEmpleado = new daEmpleado();
                    lbeEmpleado = odaEmpleado.Listar(con);
                }
                catch (SqlException ex)
                {
                    foreach (SqlError err in ex.Errors)
                    {
                        //GrabarLog
                    }
                }
                catch (Exception ex)
                {
                    //GrabarLog
                }
            } //con.close(); con.Dispose();
            return (lbeEmpleado);
        }
    }
}

Nota: Hay que referenciar a las librería "System.Configuration", la librería de entidades de negocio y de acceso a datos.

Crear una Aplicación Web de ASP.NET MVC4 en C#

Abrir el Visual Studio 2012 y seleccionar un nuevo proyecto de tipo: "Aplicación web de ASP.NET MVC4".

Escribir como nombre "Demo09" y "Aceptar", en el siguiente diálogo seleccionar la opción "Vacio" y como motor de vista "Razor" y "Aceptar".

Antes de empezar a programar debemos referenciar las librerías anteriormente creadas, es decir, la librería de entidades del negocio, de acceso a datos y de reglas del negocio de Northwind.

Crear un Controlador para el Empleado

Clic derecho a la carpeta "Controllers" y seleccionar "Agregar" y luego "Controlador", llamarle al archivo "EmpleadoController.cs" y en opciones de plantillas dejarlo en plantilla vacia (Vaciar Controlador MVC). Luego escribir el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Northwind.Librerias.EntidadesNegocio;
using Northwind.Librerias.ReglasNegocio;

namespace Demo09.Controllers
{
    public class EmpleadoController : Controller
    {
        List<beEmpleado> lbePagina;
        List<beEmpleado> lbeEmpleado;
        int indicePaginaActual;
        int indiceUltimaPagina;
        int registrosPorPagina = 10;

        private void mostrarPagina()
        {            
            lbePagina = new List<beEmpleado>();
            int inicio = indicePaginaActual * registrosPorPagina;
            int fin = inicio + registrosPorPagina;
            for (int i = inicio; i < fin; i++)
            {
                if (i==lbeEmpleado.Count) break;
                lbePagina.Add(lbeEmpleado[i]);
            }
        }

        public ActionResult Lista()
        {
            brEmpleado obrEmpleado = new brEmpleado();
            lbeEmpleado = obrEmpleado.listar();
            Session["Empleados"] = lbeEmpleado;
            indiceUltimaPagina = (lbeEmpleado.Count / registrosPorPagina);
            if (lbeEmpleado.Count % registrosPorPagina == 0) indiceUltimaPagina--;
            ViewBag.IndiceUltimaPagina = indiceUltimaPagina;
            mostrarPagina();
            return View(lbePagina);
        }

        public PartialViewResult Ordenar(string campo)
        {
            ViewBag.Campo = campo;
            lbeEmpleado = (List<beEmpleado>)Session["Empleados"];
            int n = 0;
            string simbolo = "▲";
            if (TempData[campo] != null)
            {
                if (TempData[campo].Equals(0))
                {
                    n = 1;
                    simbolo = "▼";
                }
                else simbolo = "▲";
            }
            TempData[campo] = n;
            ViewBag.Simbolo = simbolo;
            if (n == 0) lbeEmpleado = lbeEmpleado.OrderBy
            (x => x.GetType().GetProperty(campo).GetValue(x, null)).ToList();
            else lbeEmpleado = lbeEmpleado.OrderByDescending
            (x => x.GetType().GetProperty(campo).GetValue(x, null)).ToList();
            Session["Empleados"] = lbeEmpleado;
            if (TempData["indicePaginaActual"] != null)
            {
                indicePaginaActual = (int)TempData["indicePaginaActual"];
                TempData["indicePaginaActual"] = indicePaginaActual;
            }
            mostrarPagina();
            return PartialView("Tabla", lbePagina);
        }

        public PartialViewResult Paginar(int pagina)
        {
            lbeEmpleado = (List<beEmpleado>)Session["Empleados"];
            indicePaginaActual = pagina;
            TempData["indicePaginaActual"] = indicePaginaActual;
            mostrarPagina();
            return PartialView("Tabla", lbePagina);
        }
    }
}

Nota: Inicialmente se llamará al método de acción "Lista" y luego los Ajax.ActionLink de ordenar llamarán a la acción "Ordenar" que devolverá una vista parcial llamada "Tabla" con los datos ordenados ascendente o descendente de acuerdo al valor del TempData de cada campo.
Si se da clic a los Ajax.ActionLink de paginación se llamará a la acción "Paginar" que configura el "indicePaginaActual" y muestra la vista parcial "Tabla" paginada.

Crear una Hoja de Estilos para la Vista Principal y la Vista Parcial

Primero crear una carpeta llamada "Content", luego clic derecho "Agregar" y luego "Hoja de estilos" y como nombre llamarle "ACME.css" y escribir el siguiente código:

body {
    background-color:gray;
}
.Titulo {
    background-color:black;
    color:white;
    font-size:larger;
}
.Subtitulo {
    background-color:white;
    color:black;
    font-size:large;
}
.AnchoTotal {
    width:100%;
}
.Centrado {
    text-align:center;
}
.FilaCabecera {
    background-color:lightgray;
    color:black;
}
.FilaDatos {
    background-color:white;
    color:black;
}

Crear el archivo JavaScript con el código cliente para la Vista Principal

Antes que nada crear una carpeta llamada "Scripts" y arrastrar del explorador de Windows los archivos de jQuery: "jquery-1.8.2.min.js" y "jquery.unobtrusive-ajax.min.js", luego agregar un archivo de JavaScript llamado "Rutinas.js" y escribir el siguiente código:

function mostrarSimbolo() {
    var campo = document.getElementById("hdfCampo").value;
    var simbolo = document.getElementById("hdfSimbolo").value;
    var span = document.getElementById("spn" + campo);
    span.innerHTML = simbolo;
}

Nota: Los dos campos ocultos serán creados en la vista parcial y se usan para actualizar el símbolo de ordenación en la vista principal.

Crear la Vista Principal

Ir al controlador "Empleado" y ubicarse sobre el método "Lista" (acción), clic derecho y seleccionar "Agregar vista", desmarcar todas las casillas (checkboxs) y agregar la vista llamada "Lista", luego escribir el siguiente código:

@using Northwind.Librerias.EntidadesNegocio
@model List<beEmpleado>
@{
    Layout = null;
    AjaxOptions configura = new AjaxOptions{ HttpMethod="get", InsertionMode=InsertionMode.Replace, UpdateTargetId="tbEmpleado", OnComplete="mostrarSimbolo"};
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Lista</title>
    <link href="~/Content/ACME.css" rel="stylesheet" />
</head>
<body>
    <div>
        <table class="AnchoTotal">
            <tr class="Titulo">
                <td>Demo 09: Grilla Paginada y Ordenada Asíncrona con 
                       Ajax ActionLink y Vista Parcial</td>
            </tr>
            <tr class="Subtitulo">
                <td>Consulta de Empleados</td>
            </tr>
            <tr>
                <td>
                    <table class="AnchoTotal">
                        <thead>
                            <tr class="FilaCabecera">
                                <td style="width:70px">
                                    @Ajax.ActionLink("Código","Ordenar",
                                     new {campo="IdEmpleado"},configura)
                                    @Html.Raw(" ")<span id="spnIdEmpleado"></span>
                                </td>
                                <td style="width:200px">
                                    @Ajax.ActionLink("Apellido","Ordenar",
                                     new {campo="Apellido"},configura)
                                    @Html.Raw(" ")<span id="spnApellido"></span>
                                </td>
                                <td style="width:200px">
                                    @Ajax.ActionLink("Nombre","Ordenar",
                                     new {campo="Nombre"},configura)
                                    @Html.Raw(" ")<span id="spnNombre"></span>
                                </td>
                                <td style="width:100px">
                                    @Ajax.ActionLink("Fecha Nac","Ordenar",
                                     new {campo="FechaNacimiento"},configura)
                                    @Html.Raw(" ")<span id="spnFechaNacimiento"></span>
                                </td>
                            </tr>
                        </thead>
                        <tbody id="tbEmpleado">
                            @Html.Partial("Tabla",Model)
                        </tbody>
                        <tfoot>
                            <tr class="FilaCabecera">
                                <td colspan="4" class="Centrado">
                                    @for (int i = 0; i <= ViewBag.IndiceUltimaPagina; i++)
                                    {
                                        @Ajax.ActionLink((i + 1).ToString(), "Paginar", 
                                         new { pagina=i}, configura)                                        
                                        @Html.Raw("  ")
                                    }
                                </td>
                            </tr>
                        </tfoot>
                    </table>
                </td>
            </tr>
        </table>
    </div>
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
    <script src="~/Scripts/Rutinas.js"></script>
</body>
</html>

Crear la Vista Parcial

Ir al controlador "Empleado" y ubicarse sobre el método "Lista" (acción), clic derecho y seleccionar "Agregar vista", seleccionar la casilla (check) "Crear como vista parcial" y agregar la vista llamada "Tabla", luego escribir el siguiente código:

@using Northwind.Librerias.EntidadesNegocio
@model List<beEmpleado>
@foreach (beEmpleado obeEmpleado in Model)
{
    <tr class="FilaDatos">
        <td>@obeEmpleado.IdEmpleado</td>
        <td>@obeEmpleado.Apellido</td>
        <td>@obeEmpleado.Nombre</td>
        <td>@obeEmpleado.FechaNacimiento.ToShortDateString()</td>
    </tr>
}
<input id="hdfCampo" type="hidden" value="@ViewBag.Campo" />
<input id="hdfSimbolo" type="hidden" value="@ViewBag.Simbolo" />

Nota: Es necesario que los dos campos ocultos se encuentren dentro de la vista parcial para que se actualicen con el nombre del campo y el símbolo que se va a mostrar al hacer la ordenación asíncrona.

Modificar el archivo Web.Config para incluir la cadena de conexión

Ir al archivo Web.config ubicado en la raíz del proyecto e incluir lo siguiente:

<connectionStrings>
    <add name="conNW" providerName="SQLServer" connectionString=
"uid=UsuarioNW;pwd=123456;server=DSOFT\Sqlexpress;database=Northwind"/>
</connectionStrings>

Nota: Cambiar el nombre del servidor, el usuario y la clave de acuerdo a su configuración.

Configurar la Acción de Inicio

Para probar la aplicación web debemos configurar el inicio para lo cual nos vamos a la carpeta "App_Start" y abrimos el archivo "RouteConfig.cs" cambiando el nombre del controlador y la acción tal como se muestra en el siguiente código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace Demo09
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Empleado", action = "Lista", id = UrlParameter.Optional }
            );
        }
    }
}

Ejecutar y Probar la Aplicación Web

Finalmente, grabar y pulsar F5 para ejecutar la aplicación, mostrándose el resultado similar a la siguiente figura:


Probar la ordenación ascendente y descendente por cada columna y se mostrará similar a la siguiente figura:


Finalmente, navegar por cada página y se verá los datos similar a la siguiente figura:


Comentario Final

En este post, hemos aprendido como paginar y ordenar en forma asíncrona usando los controles Helpers Ajax.ActionLink de ASP.NET MVC para mostrar los datos de los empleados.

Como siempre en este Blog no hemos necesitado de ningún control de terceros para realizar estas operaciones, sino que lo hemos hecho con los controles y librerías que vienen con el Framework de ASP.NET MVC.

Descarga del código

Video del Demo


Mañana publicaré otro Demo interesante de como hacer lo mismo pero totalmente desconectado, es decir sin ir al servidor web ni al servidor de datos.

Si les gusto compartanlo y denle like o +.

miércoles, 4 de marzo de 2015

El Libro del Día: Bootstrap for ASP.NET MVC

El Libro del Día: 2015-03-04

Titulo: Bootstrap for ASP.NET MVC
Autor: Pieter van der Westhuizen
Editorial: Packt
Nro Paginas: 198

Capítulos:
Chapter 1: Getting Started with ASP.NET MVC and Bootstrap
Chapter 2: Using Bootstrap CSS and HTML Elements
Chapter 3: Using Bootstrap Components
Chapter 4: Using Bootstrap JavaScript Plugins
Chapter 5: Creating ASP.NET MVC Bootstrap Helpers
Chapter 6: Creating T4 Templates to Scaffold Bootstrap Views
Chapter 7: Converting a Bootstrap HTML Template into a Usable ASP.NET MVC Project
Chapter 8: Using the jQuery DataTables Plugin with Bootstrap
Chapter 9: Making Things Easier with the TwitterBootstrapMVC Library
Appendix: Bootstrap Resources

Descarga:
Bootstrap_for_ASP.NET_MVC

martes, 20 de enero de 2015

El Demo del Día: TreeView con CheckBox en ASP.NET MVC

TreeView con CheckBox en ASP.NET MVC

Introducción a ASP.NET MVC

El Modelo Vista Controlador es un Modelo o Patrón de Arquitectura de Desarrollo de Software que permite la separación de la lógica en 3 componentes:
- El Modelo: Contiene la lógica del dominio, como las entidades del negocio.
- La Vista: Representa la interface de usuario de la aplicación, por ejemplo las páginas y controles.
- El Controlador: Controla la interacción del usuario con la vista y la asocia a un modelo.

ASP.NET MVC es la implementación de Microsoft de este modelo o patrón como alternativa a los WebForms de ASP.NET, el cual presenta las siguientes ventajas:
- Facilita la administración de la complejidad al separar la lógica en 3 componentes.
- Reduce el HTML enviado al cliente al no usar el estado de vista (ViewState)
- Proporciona una mayor compatibilidad con el desarrollo basado en pruebas (TDD), etc.

A partir de ASP.NET MVC 3 podemos elegir crear las vistas usando 2 motores:
- WebForm: Es el mismo que se usa para crear los Sitios ASP.NET con WebForms, es decir para el código incrustado del servidor se usa: <%= %>, <%: %> o <%# %>.
- Razor: Es un nuevo motor creado especialmente para aplicaciones MVC y usa código incrustado del servidor mediante @.
Nota: Se recomienda usar Razor como motor de vista predeterminado, ya que su sintaxis es mas corta y maneja mejor el tema de codificación y de-codificación.

Para los que recién inician con ASP.NET MVC el inconveniente principal aparte de acostumbrarse al nuevo modelo, es la falta de variedad de controles para crear las vistas, ya que los controles que ofrece Microsoft son los Helpers (no son muchos) que se clasifican en 3:
- HTML Helpers: Form, Label, TextBox, CheckBox, ListBox, DropDownList, ActionLink, etc.
- AJAX Helpers: Form, ActionLink, RouteLink y Script.
- URL Helpers: Action, Content, Encode, HttpRouteUrl.

Quizás los controles que mas extrañen los programadores es los enlazados a datos como GridView, DataList, Repeater, ListView, TreeView, Chart, etc. Aunque si bien es cierto no vienen como Helpers se pueden implementar en forma personalizada, por ejemplo en este primer post de MVC trataremos sobre como crear un TreeView con CheckBox.

Requerimiento

Se desea mostrar una lista de empleados en forma jerárquica de acuerdo a su cargo, para lo cual cada empleado tiene un único jefe. La aplicación debe permitir seleccionar un empleado y automáticamente deberá seleccionarse todos sus dependientes.
Nota: La aplicación debe ser Web y estar en ASP.NET MVC4.

Solución

Para cubrir estos requerimientos se creará un TreeView con CheckBox para lo cual se realizará lo siguiente:
- El el Modelo se creará una Entidad llamada "beEmpleado".
- En el Controlador se creará un método "obtenerEmpleados" que llene una lista con los empleados.
- En el Controlador se creará un método de acción llamado "Lista" que devuelva una vista (ViewResult).
- En el Controlador se creará un método de acción llamado "Listar" que devuelva la lista en formato JSON (JsonResult).
- Desde la Vista "Lista", al cargar la página usando jQuery Ajax se llamará al método "Listar" que devuelve los datos como JavaScript Object Notation (JSON).
- Mediante JavaScript mostraremos los datos en una Tabla
- Mediante jQuery mostraremos los datos en un div creando una lista con viñetas (ul - li) conteniendo CheckBoxs.
- Usando jQuery se programará la selección jerárquica, es decir al marcar o desmarcar un empleado, debe expandirse a todos sus subordinados.
- Usando jQuery se programará el expandir o colapsar un nodo (empleado) del TreeView.

Crear una Aplicación Web de ASP.NET MVC4 en C#

Abrir el Visual Studio 2012 y seleccionar un nuevo proyecto de tipo: "Aplicación web de ASP.NET MVC4", tal como se muestra en la siguiente figura:


Se mostrará una ventana para seleccionar la plantilla de proyecto, similar a la mostrada en la siguiente figura:


Seleccionar la opción "Vacio" y como motor de vista "Razor" y "Aceptar". En la ventana del Explorador de Soluciones se verá la siguiente estructura de carpetas:


Nota: Apreciar como viene predefinida las carpetas para los Controladores, los Modelos y las Vistas.
Además viene una carpeta App_Start para configurar los inicios de la aplicación.

Crear un Modelo con la Entidad del Empleado

Clic derecho a la carpeta Models y seleccionar "Agregar" y luego "Clase", llamarle al archivo "beEmpleado.cs" y escribir el siguiente código:

namespace TreeView_CheckBox.Models
{
    public class beEmpleado
    {
        public int IdEmpleado { get; set; }
        public string Nombres { get; set; }
        public int IdJefe { get; set; }
    }
}

Crear un Controlador para el Empleado

Clic derecho a la carpeta Controllers y seleccionar "Agregar" y luego "Controlador" y se mostrará una ventana similar a la siguiente figura:


Llamarle al archivo "EmpleadoController.cs" y en opciones de plantillas dejarlo en plantilla vacia (Vaciar Controlador MVC). Luego escribir el siguiente código:

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

namespace TreeView_CheckBox.Controllers
{
    public class EmpleadoController : Controller
    {
        List<beEmpleado> lbeEmpleado;

        private void obtenerEmpleados()
        {
            lbeEmpleado = new List<beEmpleado>();
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 1, Nombres = "Luis Dueñas",
                                          IdJefe = 0 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 2, Nombres = "Arturo Castañeda",
                                          IdJefe = 1 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 3, Nombres = "Enrique Espinal",
                                          IdJefe = 1 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 4, Nombres = "Maria Rojas",
                                          IdJefe = 2 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 5, Nombres = "Juan Perez",
                                          IdJefe = 2 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 6, Nombres = "Rosa Toro",
                                          IdJefe = 3 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 7, Nombres = "Pedro Vasquez",
                                          IdJefe = 3 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 8, Nombres = "Cesar Ramirez",
                                          IdJefe = 5 });
            lbeEmpleado.Add(new beEmpleado { IdEmpleado = 9, Nombres = "Ana Rodriguez",
                                          IdJefe = 6 });
        }

        public ViewResult Lista()
        {
            return View();
        }

        public JsonResult Listar()
        {
            JsonResult rpta;
            obtenerEmpleados();
            rpta = Json(lbeEmpleado, JsonRequestBehavior.AllowGet);
            return rpta;
        }
    }
}

Crear una Hoja de Estilos para la Vista

Primero crear una carpeta llamada "Content", luego clic derecho "Agregar" y luego "Hoja de estilos" y como nombre llamarle "ACME.css" y escribir el siguiente código:

body {
    background-color:lightgray;
}
.Titulo {
    background-color:black;
    color:white;
    font-size:x-large;
    text-transform:uppercase;
}
.Subtitulo {
    background-color:white;
    color:black;
    font-size:large;
    text-transform:capitalize;
}
.AnchoTotal {
    width:100%;
}
.FilaCabecera {
    background-color:gray;
    color:white;
}
.FilaDatos {
    background-color:white;
    color:blue;
}

Crear la Vista para mostrar los datos

Ir al controlador y ubicarse sobre el método "Lista" (acción), clic derecho y seleccionar "Agregar vista", aparecerá un diálogo como se muestra en la siguiente figura:


Desmarcar todas las casillas (checkboxs) y agregar la vista llamada "Lista", luego escribir el siguiente código:

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Lista</title>
    <link href="~/Content/ACME.css" rel="stylesheet" />
    <link href="~/Content/TreeView.css" rel="stylesheet" />
</head>
<body>
    <div>
        <table class="AnchoTotal">
            <tr class="Titulo">
                <td colspan="2">TreeView con CheckBox en ASP.NET MVC usando
                                             JSON, jQuery y Ajax</td>
            </tr>
            <tr class="Subtitulo">
                <td colspan="2">Lista de Empleados</td>
            </tr>
            <tr>
                <td style="width:50%">
                    <table class="AnchoTotal">
                        <thead>
                            <tr class="FilaCabecera">
                                <td style="width:100px">Id Emp</td>                        
                                <td style="width:300px">Nombres</td>
                                <td style="width:100px">Id Jefe</td>
                            </tr>
                        </thead>
                        <tbody id="tblEmpleado">
                        </tbody>
                    </table>
                </td>
                <td style="width:50%; vertical-align:top">
                    <div id="divEmpleado">
                        <ul id="ulEmpleado"></ul>
                    </div>
                </td>
            </tr>
        </table>
    </div>
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
    <script src="~/Scripts/Rutinas.js"></script>
    <script>cargarLista();</script>
</body>
</html>

Crear el archivo JavaScript con el código cliente para el TreeView

Antes que nada crear una carpeta llamada "Scripts" y arrastrar del explorador de Windows los archivos de jQuery: "jquery-1.8.2.min.js" y "jquery.unobtrusive-ajax.min.js", luego agregar un archivo de JavaScript llamado "Rutinas.js" y escribir el siguiente código:

function cargarLista() {
    $.ajax(
        {
            url: "Empleado/Listar/",
            type: "post",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: exito,
            error: error
        });
}

function mostrarTabla(rpta) {
    var tabla = "";
    for (i = 0; i < rpta.length; i++) {
        tabla += "<tr class='FilaDatos'><td>" + rpta[i].IdEmpleado + "</td><td>" +
            rpta[i].Nombres + "</td><td>" + rpta[i].IdJefe + "</td></tr>";
    }
    var tbl = document.getElementById("tblEmpleado");
    tbl.innerHTML = tabla;
}

function mostrarTreeCheck(rpta) {
    var ul = $("#ulEmpleado");
    for (var i = 0; i < rpta.length; i++) {
        var li = "<li data-id='" + rpta[i].IdEmpleado + "'><input type='checkbox' />
                      <span style='cursor:pointer'>" + rpta[i].Nombres + "</span></li>";
        var padre;
        if (rpta[i].IdJefe == "0") padre = ul;
        else {
            var $elem = ul.find("li[data-id='" + rpta[i].IdJefe + "']");
            if ($elem.find("ul").length == 0) $elem.append("<ul>");
            padre = $elem.find("ul:first");
        }
        padre.append(li);
    }
}

function seleccionarTreeCheck() {
    $(function () {
        $("input[type='checkbox']").change(function () {
            $(this).siblings('ul')
                   .find("input[type='checkbox']")
                   .prop('checked', this.checked);
        });
    });
}

function expandirColapsarTreeCheck() {
    $(function () {
        $('#ulEmpleado').find('span').click(function (e) {
            $(this).parent().children('ul').toggle();
        });
    });
}

function exito(rpta) {
    mostrarTabla(rpta);
    mostrarTreeCheck(rpta);
    seleccionarTreeCheck();
    expandirColapsarTreeCheck();
}

function error(rpta) {
    alert(rpta.statusText);
}

Configurar el inicio y ejecutar la aplicación web

Para probar la aplicación web debemos configurar el inicio para lo cual nos vamos a la carpeta "App_Start" y abrimos el archivo "RouteConfig.cs" cambiando el nombre del controlador y la acción tal como se muestra en el siguiente código:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace JS01_TreeView_CheckBox
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Empleado", action = "Lista", id = UrlParameter.Optional }
            );
        }
    }
}

Finalmente, grabar y pulsar F5 para ejecutar la aplicación, mostrándose el resultado similar a la siguiente figura:


Seleccionar el primer empleado y ver como se marcan todos los empleados, tal como se muestra en la siguiente figura:


Dar clic sobre el segundo empleado y notar como se colapsa (oculta) sus subordinados, también colapsar el tercer empleado y el resultado será similar a la siguiente figura:


Comentario Final

En este post, un poco grande, hemos querido iniciar los Demos dedicados a ASP.NET MVC, empezando por la creación de un control TreeView con CheckBox que seleccione en forma jerárquica y expanda y colapse sus elementos.

Un camino hubiera sido usar Librerías de Controles de terceros como jQueryUI, Telerik KendoUI, Infragistics, DevExpress, etc. Pero como siempre el objetivo de este blog es enseñar a hacerlo uno mismo, para lo cual usamos JSON, JavaScript, jQuery y Ajax.

Espero les guste y si es así lo pueden re-postear en sus redes sociales: Google+, Facebook, Twitter, etc.

Descarga
2015_01_20_DemoDia_TreeView_CheckBox

sábado, 2 de agosto de 2014

El Libro del Día: Pro ASP.NET MVC 4

El Libro del Día: 2014-08-02

Titulo: Pro ASP.NET MVC 4 (4th Edition)
Autor: Adam Freeman
Editorial: Apress
Nro Paginas: 738

Capítulos:
Part 1: Introducing ASP.NET MVC 4
Chapter 1: What’s the Big Idea?
Chapter 2: Your First MVC Application
Chapter 3: The MVC Pattern
Chapter 4: Essential Language Features
Chapter 5: Working with Razor
Chapter 6: Essential Tools for MVC
Chapter 7: SportsStore - A Real Application
Chapter 8: SportsStore: Navigation
Chapter 9: SportsStore: Completing the Cart
Chapter 10: SportsStore: Administration
Chapter 11: SportsStore: Security & Finishing Touches
Part 2: ASP.NET MVC 4 in Detail
Chapter 12: Overview of MVC Projects
Chapter 13: URL Routing
Chapter 14: Advanced Routing Features
Chapter 15: Controllers and Actions
Chapter 16: Filters
Chapter 17: Controller Extensibility
Chapter 18: Views
Chapter 19: Helper Methods
Chapter 20: Templated Helper Methods
Chapter 21: URL and Ajax Helper Methods
Chapter 22: Model Binding
Chapter 23: Model Validation
Chapter 24: Bundles and Display Modes
Chapter 25: Web API
Chapter 26: Deployment

Descarga:
Pro_ASPNET_MVC4