jueves, 13 de noviembre de 2014

El Demo del Día: Filtrar en Cabeceras del GridView con Totales en el Pie y Filas de Color

Filtrar en Cabeceras del GridView con Totales en el Pie y Filas de Color

El post que viene es muy interesante ya que es un 3 en 1. Se trata de una GridView en ASP.NET Web Forms que permita filtrar mediante controles en la cabecera, mostrar el número de registros encontrados en el pie y mostrar de color las palabras buscadas en los filtros en los registros encontrados.

Requerimiento

Se necesita crear una consulta web con los siguientes requerimientos:
- La consulta debe ser desconectada y no ir a a cada momento al servidor de datos.
- Los filtros deben ser por todos los campos mostrados y deben ocupar poco espacio.
- Se debe ver de color rojo la palabra buscada en cada columna donde se ingrese un criterio de búsqueda.
- Se debe mostrar la cantidad de registros encontrados en la parte inferior.

Solución

- Usaremos el control GridView y personalizaremos la cabecera, el pie y los registros usando plantilla de datos en Web Forms (Data Template).

- Además usaremos el Enlace de Datos para conservar los valores de los campos buscados en las cabeceras ya que se pierden al ir al servidor web.

- Usaremos funciones de lado del servidor para formatear la cabecera a mostrar asi como los valores de los registros que coincidan con la palabra buscada. En esta última parte usaremos Reflection para obtener el valor de cada propiedad del objeto cabecera.

Nota: Muchos desarrolladores usan controles de terceros para cubrir este requerimiento porque no conocen bien el tema de plantillas de datos, código incrustado del servidor y por supuesto Reflection.

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

Create Procedure uspProductsListar
As
Select ProductID,ProductName,SupplierID,CategoryID,UnitPrice,UnitsInStock
From Products

Crear la Aplicación Web en ASP .NET Web Form

Crear un "Nuevo Sitio web vacío de ASP .NET" en C# llamado "GridView_FiltroCabecera_RptaColor".
Para simplificar el Demo no he creado librerías de clases y las clases las he incluido dentro de la aplicación Web.

Crear la Clase Entidad del Negocio

Crear la clase beProducto escribiendo el siguiente código:

using System;
namespace GridView_FiltroCabecera_RptaColor
{
    public class beProducto
    {
        public beProducto()
        {
            IdProducto = -1;
            IdProveedor = -1;
            IdCategoria = -1;
            PrecioUnitario = -1;
            Stock = -1;
        }
        public int IdProducto { get; set; }
        public string Nombre { get; set; }
        public int IdProveedor { get; set; }
        public int IdCategoria { get; set; }
        public decimal PrecioUnitario { get; set; }
        public short Stock { get; set; }
    }
}

Nota: Se ha creado un constructor para iniciar las propiedades numéricas en -1 y asi poder permitir la búsqueda del cero (0) en los filtros.

Crear la Clase de Acceso a Datos

Crear la clase daProducto escribiendo el siguiente código:

using System;
using System.Data; //CommadType
using System.Data.SqlClient; //SqlConnection, SqlCommand, SqlDataReader
using System.Collections.Generic; //List
namespace GridView_Paginado_Checks
{
    public class daProducto
    {
        public List<beProducto> listar(SqlConnection con)
        {
            List<beProducto> lbeProducto = null;
            SqlCommand cmd = new SqlCommand("uspProductsListar", con);
            cmd.CommandType = CommandType.StoredProcedure;
            SqlDataReader drd = cmd.ExecuteReader(CommandBehavior.SingleResult);
            if (drd != null)
            {
                lbeProducto = new List<beProducto>();
                int posIdProducto = drd.GetOrdinal("ProductID");
                int posNombre = drd.GetOrdinal("ProductName");
                int posIdProveedor = drd.GetOrdinal("SupplierID");
                int posIdCategoria = drd.GetOrdinal("CategoryID");
                int posPrecioUnitario = drd.GetOrdinal("UnitPrice");
                int posStock = drd.GetOrdinal("UnitsInStock");
                beProducto obeProducto;
                while (drd.Read())
                {
                    obeProducto = new beProducto();
                    obeProducto.IdProducto = drd.GetInt32(posIdProducto);
                    obeProducto.Nombre = drd.GetString(posNombre);
                    obeProducto.IdProveedor = drd.GetInt32(posIdProveedor);
                    obeProducto.IdCategoria = drd.GetInt32(posIdCategoria);
                    obeProducto.PrecioUnitario = drd.GetDecimal(posPrecioUnitario);
                    obeProducto.Stock = drd.GetInt16(posStock);
                    lbeProducto.Add(obeProducto);
                }
                drd.Close();
            }
            return (lbeProducto);
        }
    }
}

Nota: Tiene que haberse creado el Procedimiento Almacenado "uspProductsListar" en la BD Northwind.

Crear la Clase de Reglas del Negocio

Crear la clase brProducto escribiendo el siguiente código:

using System;
using System.Collections.Generic; //List
using System.Data.SqlClient; //SqlConnection
using System.Configuration; //ConfigurationManager
namespace GridView_Paginado_Checks
{
    public class brProducto
    {
        public List<beProducto> listar()
        {
            List<beProducto> lbeProducto = null;
            string conexion = ConfigurationManager.ConnectionStrings["conNW"].ConnectionString;
            using (SqlConnection con = new SqlConnection(conexion))
            {
                try
                {
                    con.Open();
                    daProducto odaProducto = new daProducto();
                    lbeProducto = odaProducto.listar(con);
                }
                catch (SqlException ex)
                {                  
                    foreach (SqlError err in ex.Errors)
                    {
                        //Capturar cada error y grabar un Log
                    }
                }
            } //con.Close(); con.Dispose(); con = null;
            return (lbeProducto);
        }
    }
}

Nota: Hay que hacer referencia a la librería "System.Configuration.dll" para usar la clase ConfigurationManager para leer el archivo de configuración.

Crear el Archivo de Hoja de Estilo

Agregar un archivo de hoja de estilo llamado ACME.css y escribir lo siguiente:

body {
    background-color:aqua;
}
.Titulo {
    background-color:black;
    color:white;
    text-transform:uppercase;
    font-size:xx-large;
    font-weight:bold;
}
.AnchoTotal {
    width:100%;
}
.Centrado {
    text-align:center;
}
.Subtitulo {
    background-color:white;
    color:blue;
    text-transform:capitalize;
    font-size:x-large;
    font-weight:bold;
}
.FilaCabecera {
    background-color: blue;
    color:white;
}
.FilaDatos {
    background-color: white;
    color:blue;
}

Crear la Pagina ASP .NET como un Formulario Web Form

Agregar un Formulario Web Form al proyecto llamado: "ConsultaProductos.aspx" y escribir lo siguiente:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ConsultaProductos.aspx.cs" Inherits="GridView_FiltroCabecera_RptaColor.ConsultaProductos" %>
<%@ Import Namespace="GridView_FiltroCabecera_RptaColor" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Consulta de Productos</title>
    <link href="ACME.css" rel="stylesheet" type="text/css" />
    <script>
        function filtrar(event) {
            var keyCode = ('which' in event) ? event.which : event.keyCode;
            if (keyCode == 13) {
                var btn = document.getElementById("btnFiltrar");
                if (btn != null) btn.click();
                return false;
            }
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <table class="AnchoTotal">
            <tr class="Titulo">
                <td>GridView Filtros Cabecera, Total Pie y Filas Color</td>
            </tr>
            <tr class="Subtitulo">
                <td>Consulta Desconectada de Productos (Autor: Luis Dueñas)</td>
            </tr>
            <tr>
                <td>
                    <asp:GridView ID="gvProducto" AutoGenerateColumns="false" ShowFooter="true"
                        Width="700px" ShowHeaderWhenEmpty="true" runat="server">
                        <HeaderStyle CssClass="FilaCabecera" />
                        <RowStyle CssClass="FilaDatos" />
                        <FooterStyle CssClass="FilaCabecera" />
                        <Columns>
                            <asp:TemplateField HeaderText="" ItemStyle-Width="80px"
                              ItemStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Código<br />
                                    <asp:TextBox ID="txtIdProducto"
                                      Text="<%#formatearNumero(obeProductoCab.IdProducto)%>"
                                      onkeypress="return filtrar(event);" Width="80px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                            IdProducto.ToString(),"IdProducto")%>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField ItemStyle-Width="300px"
                              FooterStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Descripción del Producto<br />
                                    <asp:TextBox ID="txtNombre" Text="<%#obeProductoCab.Nombre%>"
                                      onkeypress="return filtrar(event);" Width="300px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                            Nombre,"Nombre")%>
                                </ItemTemplate>
                                <FooterTemplate>
                                    <b>Total de Registros encontrados: </b>
                                </FooterTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField ItemStyle-Width="80px" ItemStyle-HorizontalAlign="Right"
                              FooterStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Id Prov<br />
                                    <asp:TextBox ID="txtIdProveedor"
                                      Text="<%#formatearNumero(obeProductoCab.IdProveedor)%>"
                                      onkeypress="return filtrar(event);" Width="80px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                            IdProveedor.ToString(),"IdProveedor")%>
                                </ItemTemplate>
                                <FooterTemplate>
                                    <b><%#lbeFiltro.Count%></b>
                                </FooterTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField ItemStyle-Width="80px" ItemStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Id Cat<br />
                                    <asp:TextBox ID="txtIdCategoria"
                                       Text="<%#formatearNumero(obeProductoCab.IdCategoria)%>"
                                      onkeypress="return filtrar(event);" Width="80px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                            IdCategoria.ToString(),"IdCategoria")%>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField ItemStyle-Width="80px"
                               ItemStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Pre Unit<br />
                                    <asp:TextBox ID="txtPrecioUnitario"
                                      Text="<%#formatearNumero(obeProductoCab.PrecioUnitario)%>"
                                      onkeypress="return filtrar(event);" Width="80px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                           PrecioUnitario.ToString(),"PrecioUnitario")%>
                                </ItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField ItemStyle-Width="80px" ItemStyle-HorizontalAlign="Right">
                                <HeaderTemplate>
                                    Stock<br />
                                    <asp:TextBox ID="txtStock"
                                      Text="<%#formatearNumero(obeProductoCab.Stock)%>"
                                      onkeypress="return filtrar(event);" Width="80px" runat="server" />
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <%#formatearCelda(((beProducto)Container.DataItem).
                                            Stock.ToString(),"Stock")%>
                                </ItemTemplate>
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
                </td>
            </tr>
        </table>
        <asp:Button ID="btnFiltrar" OnClick="filtrarProductos" runat="server" />
    </div>
    </form>
</body>
</html>

Nota: El script del cliente "filtrar" se llama al dar Enter a cualquier control de la cabecera y ejecuta el clic del botón "btnFiltrar:" que es el que permite realizar el filtro y esta oculto por código.

El preview del diseño se mostrará similar a la siguiente figura:


Escribir el siguiente código C# en la página:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace GridView_FiltroCabecera_RptaColor
{
    public partial class ConsultaProductos : System.Web.UI.Page
    {
        private List<beProducto> lbeProducto;
        protected List<beProducto> lbeFiltro;
        protected beProducto obeProductoCab;

        protected void Page_Load(object sender, EventArgs e)
        {
            btnFiltrar.Attributes.Add("style", "display:none");
            obeProductoCab = new beProducto();
            if (!Page.IsPostBack)
            {
                brProducto obrProducto = new brProducto();
                lbeProducto = obrProducto.listar();
                lbeFiltro = lbeProducto;
                Session["Productos"] = lbeProducto;
                gvProducto.DataSource = lbeFiltro;
                gvProducto.DataBind();
            }
        }

        protected string formatearNumero(dynamic campo)
        {
            string cabecera = "";
            if (campo > -1) cabecera = campo.ToString();
            return (cabecera);
        }

        private bool buscarProductos(beProducto obeProducto)
        {
            bool exitoIdProducto = true;
            bool exitoNombre = true;
            bool exitoIdProveedor = true;
            bool exitoIdCategoria = true;
            bool exitoPrecioUnitario = true;
            bool exitoStock = true;
            if (obeProductoCab.IdProducto>-1) exitoIdProducto = (obeProducto.IdProducto.ToString().Contains(obeProductoCab.IdProducto.ToString()));
            if (!obeProductoCab.Nombre.Equals("")) exitoNombre = (obeProducto.Nombre.ToLower().Contains(obeProductoCab.Nombre.ToLower()));
            if (obeProductoCab.IdProveedor > -1) exitoIdProveedor = (obeProducto.IdProveedor.ToString().Contains(obeProductoCab.IdProveedor.ToString()));
            if (obeProductoCab.IdCategoria > -1) exitoIdCategoria = (obeProducto.IdCategoria.ToString().Contains(obeProductoCab.IdCategoria.ToString()));
            if (obeProductoCab.PrecioUnitario > -1) exitoPrecioUnitario = (obeProducto.PrecioUnitario.ToString().Contains(obeProductoCab.PrecioUnitario.ToString()));
            if (obeProductoCab.Stock > -1) exitoStock = (obeProducto.Stock.ToString().Contains(obeProductoCab.Stock.ToString()));
            return (exitoIdProducto && exitoNombre && exitoIdProveedor && exitoIdCategoria && exitoPrecioUnitario && exitoStock);
        }

        protected void filtrarProductos(object sender, EventArgs e)
        {
            guardarFiltros();
            lbeProducto=(List<beProducto>)Session["Productos"];
            Predicate<beProducto> pred = new Predicate<beProducto>(buscarProductos);
            lbeFiltro = lbeProducto.FindAll(pred);
            gvProducto.DataSource = lbeFiltro;
            gvProducto.DataBind();
        }

        private void guardarFiltros()
        {
            string sIdProducto = ((TextBox)gvProducto.HeaderRow.Cells[0].Controls[1]).Text;
            obeProductoCab.IdProducto = (sIdProducto.Equals("") ? -1 : int.Parse(sIdProducto));
            obeProductoCab.Nombre = ((TextBox)gvProducto.HeaderRow.Cells[1].Controls[1]).Text;
            string sIdProveedor = ((TextBox)gvProducto.HeaderRow.Cells[2].Controls[1]).Text;
            obeProductoCab.IdProveedor = (sIdProveedor.Equals("") ? -1 : int.Parse(sIdProveedor));
            string sIdCategoria = ((TextBox)gvProducto.HeaderRow.Cells[3].Controls[1]).Text;
            obeProductoCab.IdCategoria = (sIdCategoria.Equals("") ? -1 : int.Parse(sIdCategoria));
            string sPrecioUnitario = ((TextBox)gvProducto.HeaderRow.Cells[4].Controls[1]).Text;
            obeProductoCab.PrecioUnitario = (sPrecioUnitario.Equals("") ? -1 : decimal.Parse(sPrecioUnitario));
            string sStock = ((TextBox)gvProducto.HeaderRow.Cells[5].Controls[1]).Text;
            obeProductoCab.Stock = (sStock.Equals("") ? short.Parse("-1") : short.Parse(sStock));
        }

        protected string formatearCelda(string valor,string campo)
        {
            StringBuilder rpta = new StringBuilder();
            string celda = valor.ToLower();
            dynamic cabecera = obeProductoCab.GetType().GetProperty(campo).
            GetValue(obeProductoCab, null);
            if (cabecera != null)
            {
                if (!(cabecera is string) && (cabecera == -1)) return valor;
                if ((cabecera is string) && cabecera.Equals("")) return valor;
                string busca = cabecera.ToString().ToLower();
                int posInicio =0;
                int pos = celda.IndexOf(busca);
                if (pos > -1)
                {
                    while (true)
                    {
                        pos = celda.IndexOf(busca, pos);
                        if (pos > -1)
                        {
                            rpta.Append(valor.Substring(posInicio,pos-posInicio));
                            rpta.Append("<span style='color:red;font-bold:true'>");
                            rpta.Append(valor.Substring(pos, busca.Length));
                            rpta.Append("</span>");
                            posInicio = pos + busca.Length;
                            pos += 1;
                        }
                        else break;
                    }
                    rpta.Append(valor.Substring(posInicio, valor.Length - posInicio));
                }
                else rpta.Append(valor);
            }
            else rpta.Append(valor);
            return (rpta.ToString());
        }
    }
}

Nota: El código mas complejo se encuentra en la función "formatearCelda" que se llama desde cada campo de cada registro mostrado en el filtro y que pasa como parámetro el valor de la celda a presentar y el campo a buscar para la cabecera. Aquí usamos Reflection para obtener el valor de cada propiedad del objeto cabecera e iniciar la búsqueda de la palabra en el valor e ir agregando en un StringBuilder la cadena con formato (negrita y colo rojo).

También es necesario antes de "filtrarProductos" llamar a la función "guardarFiltros" que se encarga de pasar los valores de los controles de la cabecera de la grilla en el objeto enlazado a la cabecera llamado: "obeProductoCab", de lo contrario se perderían los valores ingresados.

Finalmente, hay que aclarar que para poder usar desde el código HTML (aspx) un objeto o variables es necesario definirla como protected (por herencia), este es el caso de "lbeFiltro" y "obeProductoCab".

Modificar el Archivo Web.Config para especificar la cadena de conexión a Northwind

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <connectionStrings>
    <add name="conNW" providerName="System.Data.SqlClient"
      connectionString="uid=UsuarioNW;pwd=123456;data source=DSOFT\Sqlexpress;
      initial catalog=Northwind"/>
  </connectionStrings>
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
</configuration>

Probar la Pagina Web

Guardar el Sitio Web, clic derecho a la Pagina "ConsultaProductos.aspx" y seleccionar "Ver en el explorador". Se mostrará una ventana similar a la siguiente figura:


Se listarán todos los productos de Northwind, ahora escribir sobre el control TextBox de la cabecera del nombre la palabra "ma" y pulsar "Enter" y se filtrarán los registros apareciendo la palabra "ma" de color rojo y en negrita, tal como se muestra a continuación:


Sobre este filtro aumentar un filtro más ingresando sobre la cabecera del código del producto el número "1" y se filtrará por los 2 criterios apareciendo el número "1" de color rojo y en negrita igual que la palabra "ma", tal como se muestra en la figura de abajo:


Aumentar otro filtro para el Id de la Categoría escribiendo el número "4" y se filtrará por 3 criterios, reduciéndose mas el resultado y apareciendo de color rojo y en negrita el número "4" de la categoría, tal como se ve en la figura:


Finalmente, probemos un filtro mas que no muestre ningún registro, para lo cual aumentar como cuarto filtro que el Stock tenga el número "5", lo cual no genera ningún resultado, pero la cabecera se mantiene gracias a la propiedad: ShowHeaderWhenEmpty="true".


Si deseas mostrar todos los registros borrar cada campo de la cabecera y dar Enter en cualquiera.

Comentario Final

En este post, vimos como se puede crear en un GridView cabeceras y pies personalizados, en este caso para filtrar en forma desconectada usando plantillas de datos y código incrustado del servidor, también vimos como resaltar la palabra buscada en cada columna, aunque se aprecia mejor en columnas de tipo cadena que numérico.

Espero les guste el Demo y recuerden que No es tan complicado crear su propio control Grilla Personalizada, aunque muchos No les gusta hacerse problemas y usan sus controles jGrid, trueGrid, softGrid, superGrid, etc, pero lo mejor seria el yourSelfGrid (Grid de ti mismo).

Nota: En mis cursos creo en la cabecera DropDownList (Combos) para filtrar por Proveedor y Categoría, pero no pinto de colores los registros encontrados.

PD: Los que llevan el curso de MVC los Sábados ya tienen una ayudita para terminar lo que les deje.

Descarga:
GridView_FiltroCabecera_RptaColor

El Libro del Día: WPF 4 Unleashed

El Libro del Día: 2014-11-13

Titulo: WPF 4 Unleashed
Autor: Adam Nathan
Editorial: Sams
Nro Paginas: 844

Capítulos:
Part I Background
1 Why WPF, and What About Silverlight?
2 XAML Demystified
3 WPF Fundamentals
Part II Building a WPF Application
4 Sizing, Positioning, and Transforming Elements
5 Layout with Panels
6 Input Events: Keyboard, Mouse, Stylus, and Multi-Touch
7 Structuring and Deploying an Application
8 Exploiting Windows 7
Part III Controls
9 Content Controls
10 Items Controls
11 Images, Text, and Other Controls
Part IV Features for Professional Developers
12 Resources
13 Data Binding
14 Styles, Templates, Skins, and Themes
Part V Rich Media
15 2D Graphics
16 3D Graphics
17 Animation
18 Audio, Video, and Speech
Part VI Advanced Topics
19 Interoperability with Non-WPF Technologies
20 User Controls and Custom Controls
21 Layout with Custom Panels

Descarga:
WPF_4_Unleashed

miércoles, 12 de noviembre de 2014

Entrenamiento - Nuevo Inicio PECI .NET y Charlas

Nuevo Inicio PECI .NET y Charlas

A los alumnos y profesionales interesados en capacitación y charlas de Desarrollo en .NET estoy iniciando una campaña por mejorar el nivel educativo del desarrollo en nuestro país, algo que vengo haciendo hace muchos años pero que esta vez será mas constante, para lo cual les informo lo siguiente.

Nuevo Inicio PECI .NET ISILTECH

Este Sábado 15 de Noviembre de 2:30 pm a 8:30 pm se inicia un nuevo programa PECI .NET en ISILTECH que como saben dura casi 6 meses y tiene los siguientes cursos:

1. NET Framework
2. ADO .NET
3. Windows Forms
4. ASP .NET Web Forms
5. ASP .NET MVC
6. Windows Presentation Foundation (WPF)
7. Windows Communication Foundation (WCF)
8. Windows Workflow Foundation (WF)

Es lo mas recomendado para personas que quieren aprender las buenas practicas de desarrollo en .NET y cubre la mayoría de temas.

Charlas de .NET en HTE ACEE

Para los que ya conocen .NET y quieren mejorar sus conocimientos con charlas técnicas de alto nivel y a la vez ver temas novedosos como HTML5, APIs de Google, etc, iniciamos las charlas junto con la empresa HTE, las cuales tienen un costo mínimo de 40 soles y los temas propuestos son:

1. NET Framework – Mejores Prácticas de Performance
2. NET Framework – Técnicas de Programación Asíncrona
3. NET Framework – Programando con Reflection
4. ASP .NET – Creando un Control DataGrid en MVC4
5. ASP .NET – Servicios Full REST con Web API
6. HTML5 – Nuevos Controles y Creación de Gráficos
7. HTML5 – Trabajando con Multimedia
8. Google - Maps, YouTube y Drive
9. Google - Web Components & Polymer

Los datos de la primera charla son:

Tema: NET Framework – Mejores Prácticas de Performance
Fecha: Miércoles 03 de Diciembre del 2014
Hora: 07:00 pm - 10:00 pm
Direccion: Jr. Manuel A. Segura 271 - Urb. Santa Beatriz - Lima.
Referencia: Cuadra 15 de Av. Arequipa.
Telefono HTE: 3030447

Los interesados deberán enviar un correo confirmando su asistencia a Luis.duenash@gmail.com con copia a:informes@hte.com.pe

Recuerden que las vacantes son limitadas y el pago se realizara el mismo día de la charla.
Estas serán cada 14 días (2 x mes).

Importante: Como saben trate de dar estas charlas en forma gratuita pero no se pudo, por un tema de disponibilidad de aulas, es por eso que en asociación con la empresa HTE de unos amigos estamos organizando las charlas a un costo en realidad bajo, solo para cubrir los costos fijos.

Charlas Gratuitas en Instituciones Educativas

Los días Viernes del 21 de Noviembre hasta el Viernes 19 de Diciembre de 6:00 a 8:00 pm o de 7:00 a 9:00 pm estamos dando charlas de Introducción al Desarrollo en .NET para los estudiantes de Institutos o Universidades que lleven cursos de Programación en especial los últimos ciclos.

Solo tienen que organizarse para solicitar la charla (enviando un mail a Luis.duenash@gmail.com) que sera solo los Viernes en la noche y no tendrá ningún costo, ya que la idea es motivar e incentivar a los alumnos en el fascinante mundo de la programación y darles los tips para ser buenos profesionales.

Comentario Final

Finalmente, como siempre digo en clases, para ser mejores hay que invertir en uno mismo, sobre todo muchas horas de estudio, investigación y desarrollo.

No solo es suficiente con estudiar con una carrera (para los alumnos) o con trabajar (para los profesionales) sino que hay que estar constantemente capacitándose, investigando y sobre todo en contacto con personas que nos pueden ayudar a mejorar.

Saludos y espero la participación sobre todo de los visitantes asiduos del Blog que sería bueno conocer ya que todos son importantes.

El Libro del Día: Windows Presentation Foundation 4.5 Cookbook

El Libro del Día: 2014-11-12

Titulo: Windows Presentation Foundation 4.5 Cookbook
Autor: Pavel Yosifovich
Editorial: Packt
Nro Paginas: 464

Capítulos:
Chapter 1: Foundations
Chapter 2: Resources
Chapter 3: Layout and Panels
Chapter 4: Using Standard Controls
Chapter 5: Application and Windows
Chapter 6: Data Binding
Chapter 7: Commands and MVVM
Chapter 8: Styles, Triggers, and Control Templates
Chapter 9: Graphics and Animation
Chapter 10: Custom Elements
Chapter 11: Threading

Descarga:
Windows_Presentation_Foundation_4.5_Cookbook

martes, 11 de noviembre de 2014

El Libro del Día: WPF 4.5 in C#

El Libro del Día: 2014-11-11

Titulo: Pro WPF 4.5 in C#
Autor: Matthew MacDonald
Editorial: Apress
Nro Paginas: 1095

Capítulos:
Part I: Fundamentals
Chapter 1: Introducing WPF
Chapter 2: XAML
Chapter 3: Layout
Chapter 4: Dependency Properties
Chapter 5: Routed Events
Part II: Deeper Into WPF
Chapter 6: Controls
Chapter 7: The Application
Chapter 8: Element Binding
Chapter 9: Commands
Chapter 10: Resources
Chapter 11: Styles and Behaviors
Part III: Drawing and Animation
Chapter 12: Shapes, Brushes, and Transforms
Chapter 13: Geometries and Drawings
Chapter 14: Effects and Visuals
Chapter 15: Animation Basics
Chapter 16: Advanced Animation
Part IV: Templates and Custom Elements
Chapter 17: Control Templates
Chapter 18: Custom Elements
Part V: Data
Chapter 19: Data Binding
Chapter 20: Formatting Bound Data
Chapter 21: Data Views
Chapter 22: Lists, Trees, and Grids
Part VI: Windows, Pages, and Rich Controls
Chapter 23: Windows
Chapter 24: Pages and Navigation
Chapter 25: Menus, Toolbars, and Ribbons
Chapter 26: Sound and Video
Chapter 27: 3-D Drawing
Part VII: Documents and Printing
Chapter 28: Documents
Chapter 29: Printing
Part VIII: Additional Topics
Chapter 30: Interacting with Windows Forms
Chapter 31: Multithreading
Chapter 32: The Add-in Model
Chapter 33: ClickOnce Deployment

Descarga:
Pro_WPF_4.5_C#

lunes, 10 de noviembre de 2014

El Demo del Día: Selección Jerárquica en TreeView con CheckBox

Selección Jerárquica en TreeView con CheckBox

En este post veremos como trabajar en una aplicación Windows Forms con un TreeView que tenga CheckBoxes para poder seleccionar en forma jerárquica varios nodos al marcar o desmarcar el check del nodo padre.

Requerimientos

- Se desea llenar en forma dinámica un control TreeView (estructura jerárquica) desde una Lista de Objetos (estructura matricial).

- El TreeView debe contener CheckBox para cada elemento.

- Al marcar o desmarcar el Check de un nodo deberían marcarse o desmarcarse todos sus nodos hijos.

Solución

- Usaremos el Control TreeView de Windos Forms y configuraremos la propiedad "CheckBoxes" en true para habilitar los Checks en cada nodo.

- Se usará la recursividad para cargar la lista de objetos en los nodos.

- Finalmente en el evento "AfterCheck" usando también recursividad se marcara o desmarcara los nodos hijos del nodo padre.

Crear una Aplicación Windows Forms en C#

En Visual Studio crear un proyecto Windows Forms en C# con el nombre de "TreeView_CheckBox", luego cambiar el nombre del formulario a "frmListaEmpleados".

Agregar una Clase Entidad de Negocio para el Empleado

Crearemos un ejemplo que trabaje con una lista de empleados que se cargará desde una Lista de Objetos que se llena manualmente pero puede obtenerse desde una base de datos.

Para esto hay que crear una clase llamada "beEmpleado.cs", y escribir el siguiente código:

using System;
namespace TreeView_CheckBox
{
    public class beEmpleado
    {
        public int IdEmpleado { get; set; }
        public string Nombres { get; set; }
        public int IdJefe { get; set; }
    }
}

Crear el Formulario con el TreeView con CheckBoxes

En el formulario llamado "frmListaEmpleados" agregar un TreeView llamado "tvwEmpleado" y acoplarlo a toda la ventana (Dock en Fill), luego configurar la propiedad "CheckBoxes" en true, tal como se muestra en la siguiente figura:


Escribir el siguiente código en el formulario:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace TreeView_CheckBox
{
    public partial class frmListaEmpleados : Form
    {
        List<beEmpleado> lbeEmpleado;

        public frmListaEmpleados()
        {
            InitializeComponent();
        }

        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 });
        }

        private void listarEmpleados(object sender, EventArgs e)
        {
            obtenerEmpleados();
            TreeNode nodoRaiz = new TreeNode(lbeEmpleado[0].Nombres);
            nodoRaiz.Tag = lbeEmpleado[0].IdEmpleado.ToString();
            tvwEmpleado.Nodes.Add(nodoRaiz);
            llenarTreeView(nodoRaiz);
            tvwEmpleado.ExpandAll();
        }

        private void llenarTreeView(TreeNode nodoPadre)
        {
            int idJefe = int.Parse(nodoPadre.Tag.ToString());
            List<beEmpleado> lbeFiltro = lbeEmpleado.FindAll(x => x.IdJefe.Equals(idJefe));
            if (lbeFiltro != null && lbeFiltro.Count > 0)
            {
                TreeNode nodoHijo;
                foreach (beEmpleado obeEmpleado in lbeFiltro)
                {
                    nodoHijo = new TreeNode(obeEmpleado.Nombres);
                    nodoHijo.Tag = obeEmpleado.IdEmpleado.ToString();
                    nodoPadre.Nodes.Add(nodoHijo);
                    llenarTreeView(nodoHijo);
                }
            }
        }

        private void seleccionarNodoEmpleado(object sender, TreeViewEventArgs e)
        {
            TreeNode nodoJefe = e.Node;
            seleccionarEmpleadosPorJefe(nodoJefe);
        }

        private void seleccionarEmpleadosPorJefe(TreeNode nodoJefe)
        {
            foreach (TreeNode nodoEmpleado in nodoJefe.Nodes)
            {
                nodoEmpleado.Checked = nodoEmpleado.Parent.Checked;
            }
        }
    }
}

Nota: El método "listarEmpleados" esta asociado al evento "Load" del formulario y el método "llenarTreeView" esta asociado al evento "AfterCheck" del TreeView llamado "tvwEmpleado".

Se está usando la propiedad Text de cada nodo (objeto TreeNode) para mostrar el Nombre del Empleado pero se usa la propiedad Tag para guardar el Id del Empleado.

Hay que comentar que al seleccionarse un nodo hijo nuevamente se dispara el evento "AfterCheck" es por eso que no se debe llamar al método "seleccionarEmpleadosPorJefe" así mismo ya que de por si se hace la recursividad por el evento.

Probar la Aplicación Windows Forms

Grabar la aplicación y ejecutarla con F5. Se mostrará la siguiente ventana:


Marcar el check de cualquier empleado y se marcarán todos sus subordinados, tal como se muestra en la siguiente figura:


Ahora probar a desmarcar y se desmarcan todos sus dependencias gracias a la recursividad del evento "AfterCheck".

Comentario Final

En este post vimos como trabajar con un TreeView con CheckBoxes y poder marcar o desmarcar jerárquicamente usando recursividad. Espero les sirva este ejemplo y lo mismo sería para Web.

Ya saben que se aceptan pedidos. Los pedidos mas interesantes serán considerados para programarlos y subirlos al Blog.

Descarga

El Libro del Día: Illustrated WPF

El Libro del Día: 2014-11-10

Titulo: Illustrated WPF
Autor: Daniel Solis
Editorial: Apress
Nro Paginas: 531

Capítulos:
CHAPTER 1 Introduction to Windows Presentation Foundation
CHAPTER 2 Overview of WPF Programming
CHAPTER 3 WPF Architecture and Applications
CHAPTER 4 XAML
CHAPTER 5 Layout
CHAPTER 6 Content and Controls
CHAPTER 7 Dependency Properties
CHAPTER 8 Data Binding
CHAPTER 9 Routing Events and Commands
CHAPTER 10 Other Controls and Elements
CHAPTER 11 Resources
CHAPTER 12 Styles
CHAPTER 13 Control Templates
CHAPTER 14 Page Navigation Programs
CHAPTER 15 More Data Binding
CHAPTER 16 Trees, Tabs, and Other Controls
CHAPTER 17 Text and Documents
CHAPTER 18 Graphics in WPF
CHAPTER 19 Animation
CHAPTER 20 Audio and Video

Descarga:
Illustrated_WPF