El Libro del Día: 2014-11-30
Titulo: Microsoft Sharepoint 2013 Developer Reference
Autor: Paolo Pialorsi
Editorial: Microsoft
Nro Paginas: 794
Capítulos:
Part I GETTING STARTED
Chapter 1 Microsoft SharePoint 2013: A quick tour
Chapter 2 SharePoint data fundamentals
Part II DEVELOPING SHAREPOINT SOLUTIONS
Chapter 3 Data provisioning
Chapter 4 SharePoint features and solutions
Chapter 5 Server Object Model
Chapter 6 LINQ to SharePoint
Chapter 7 Client-side technologies
Part III DEVELOPING SHAREPOINT APPS
Chapter 8 SharePoint apps
Chapter 9 The new SharePoint REST API
Chapter 10 Remote event receivers
Part IV EXTENDING SHAREPOINT
Chapter 11 Developing Web Parts
Chapter 12 Customizing the UI
Chapter 13 Web templates
Chapter 14 Business Connectivity Services
Part V DEVELOPING WORKFLOWS
Chapter 15 Windows Workflow Foundation
Chapter 16 SharePoint workflow fundamentals
Chapter 17 Developing workflows
Chapter 18 Advanced workflows
Descarga:
Microsoft_Sharepoint_2013_Developer_Reference
Blog de Luis Dueñas dedicado a la difusión del Desarrollo en Microsoft .NET, Visual Studio, WinForms, WebForms, MVC, ASP .NET, jQuery, AJAX, HTML5, JavaScript, Móviles, etc. Encontrarás Libros, Demos, Artículos Técnicos, Entrenamiento.
domingo, 30 de noviembre de 2014
El Libro del Día: Microsoft Sharepoint 2013 Developer Reference
Etiquetas:
Advanced,
Business Connectivity,
Client Side,
Developing,
Libros,
LINQ,
Microsoft,
Paolo Pialorsi,
Reference,
Remore Events,
REST API,
Services,
SharePoint,
SOM,
Web Parts,
Web Templates,
Workflow
sábado, 29 de noviembre de 2014
El Libro del Día: Microsoft Sharepoint 2013 App Development
El Libro del Día: 2014-11-29
Titulo: Microsoft Sharepoint 2013 App Development
Autor: Scot Hillier, Ted Pattison
Editorial: Microsoft
Nro Paginas: 204
Capítulos:
Chapter 1 Introducing SharePoint apps
Chapter 2 Client-side programming
Chapter 3 SharePoint app security
Chapter 4 Developing SharePoint apps
Descarga:
Microsoft_Sharepoint_2013_App_Development
Titulo: Microsoft Sharepoint 2013 App Development
Autor: Scot Hillier, Ted Pattison
Editorial: Microsoft
Nro Paginas: 204
Capítulos:
Chapter 1 Introducing SharePoint apps
Chapter 2 Client-side programming
Chapter 3 SharePoint app security
Chapter 4 Developing SharePoint apps
Descarga:
Microsoft_Sharepoint_2013_App_Development
viernes, 28 de noviembre de 2014
El Demo del Día: Preview de Imágenes en un TreeView de Directorios en WebForms
Preview de Imágenes en un TreeView de Directorios en WebForms
En este breve post veremos como mostrar los directorios de una cierta carpeta de la Aplicación Web, por ejemplo de las Imágenes. Para esto usaremos el control TreeView para mostrar jerárquicamente los directorios y el control Repeater para listar los archivos y ver las imágenes del directorio seleccionado.
Crear la Aplicación Web en ASP .NET Web Form
Crear un "Nuevo Sitio web vacío de ASP .NET" en C# llamado "TreeViewDirectorios_PreviewImagenes". Crear la siguiente estructura de carpetas en el proyecto:
- Estilos: Contiene el archivo de hoja de estilo ACME.css
- Imagenes: Contiene las carpetas Empleados y Productos
- Empleados: Contiene archivos de los empleados del 01.jpg al 08..jpg
- Productos: Contiene las siguientes carpetas
- Bebidas: Contiene archivos jpg con bebidas.
- Condimentos: Contiene archivos jpg con condimentos.
- Confecciones: Contiene archivos jpg con confecciones.
- Paginas: Contiene el formulario web VisorImagenes.aspx
Crear el Archivo de Hoja de Estilo
En la carpeta "Estilos" agregar un archivo de hoja de estilo llamado "ACME.css" y escribir lo siguiente:
Crear la Pagina como Formulario WebForm
En la carpeta "Paginas" agregar un formulario WebForm llamado: "VisorImagenes.aspx" y escribir lo siguiente:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="VisorImagenes.aspx.cs" Inherits="TreeViewDirectorios_PreviewImagenes.Paginas.VisorImagenes" %>
<!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></title>
<link href="../Estilos/ACME.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr class="Titulo">
<td colspan="2">Preview de Imagenes en un TreeView de Directorios</td>
</tr>
<tr class="Subtitulo">
<td colspan="2">Creado Por: Luis Duenas</td>
</tr>
<tr>
<td style="vertical-align:top">
<asp:TreeView ID="tvwDirectorio" runat="server"
OnSelectedNodeChanged="mostrarImagenesDirectorio"/>
</td>
<td>
<asp:Repeater ID="rptImagen" EnableViewState="false" runat="server">
<ItemTemplate>
<img src="<%#obtenerUrl(Container.DataItem.ToString())%>"
title="<%#obtenerNombre(Container.DataItem.ToString())%>"
class="Imagen" alt="" />
</ItemTemplate>
</asp:Repeater>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
En este breve post veremos como mostrar los directorios de una cierta carpeta de la Aplicación Web, por ejemplo de las Imágenes. Para esto usaremos el control TreeView para mostrar jerárquicamente los directorios y el control Repeater para listar los archivos y ver las imágenes del directorio seleccionado.
Crear la Aplicación Web en ASP .NET Web Form
Crear un "Nuevo Sitio web vacío de ASP .NET" en C# llamado "TreeViewDirectorios_PreviewImagenes". Crear la siguiente estructura de carpetas en el proyecto:
- Estilos: Contiene el archivo de hoja de estilo ACME.css
- Imagenes: Contiene las carpetas Empleados y Productos
- Empleados: Contiene archivos de los empleados del 01.jpg al 08..jpg
- Productos: Contiene las siguientes carpetas
- Bebidas: Contiene archivos jpg con bebidas.
- Condimentos: Contiene archivos jpg con condimentos.
- Confecciones: Contiene archivos jpg con confecciones.
- Paginas: Contiene el formulario web VisorImagenes.aspx
Crear el Archivo de Hoja de Estilo
En la carpeta "Estilos" agregar un archivo de hoja de estilo llamado "ACME.css" y escribir lo siguiente:
body {
background-color:lightgray;
}
.Titulo {
background-color:black;
color:white;
text-transform:uppercase;
font-size:xx-large;
font-weight:bold;
}
.Subtitulo {
background-color:white;
color:black;
text-transform:capitalize;
font-size:x-large;
font-weight:bold;
}
.Imagen {
width:120px;
height:100px;
border:solid;
border-width:20px;
border-color:lightgray;
}
.Imagen:hover {
cursor:pointer;
border:solid;
border-width:20px;
border-color:yellow;
}
Crear la Pagina como Formulario WebForm
En la carpeta "Paginas" agregar un formulario WebForm llamado: "VisorImagenes.aspx" y escribir lo siguiente:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="VisorImagenes.aspx.cs" Inherits="TreeViewDirectorios_PreviewImagenes.Paginas.VisorImagenes" %>
<!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></title>
<link href="../Estilos/ACME.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr class="Titulo">
<td colspan="2">Preview de Imagenes en un TreeView de Directorios</td>
</tr>
<tr class="Subtitulo">
<td colspan="2">Creado Por: Luis Duenas</td>
</tr>
<tr>
<td style="vertical-align:top">
<asp:TreeView ID="tvwDirectorio" runat="server"
OnSelectedNodeChanged="mostrarImagenesDirectorio"/>
</td>
<td>
<asp:Repeater ID="rptImagen" EnableViewState="false" runat="server">
<ItemTemplate>
<img src="<%#obtenerUrl(Container.DataItem.ToString())%>"
title="<%#obtenerNombre(Container.DataItem.ToString())%>"
class="Imagen" alt="" />
</ItemTemplate>
</asp:Repeater>
</td>
</tr>
</table>
</div>
</form>
</body>
</html>
Nota: Es importante que se desactive el ViewState del Repeater para dismunir el HTML generado en el cliente, ya que no es necesario, porque en el servidor se esta enlazando el control Repeater cada vez que se elige un directorio (optmización del HTML enviado al cliente).
El diseño de la pagina debe mostrase similar a la siguiente figura:
Escribir el siguiente código C# para la pagina:
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
namespace TreeViewDirectorios_PreviewImagenes.Paginas
{
public partial class VisorImagenes : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string ruta = Server.MapPath("../Imagenes");
IEnumerable<string> listaDirectorios = Directory.EnumerateDirectories(ruta);
TreeNode nodoRaiz = new TreeNode("Imagenes");
tvwDirectorio.Nodes.Add(nodoRaiz);
llenarNodos(nodoRaiz, listaDirectorios);
tvwDirectorio.ExpandAll();
tvwDirectorio.SelectedNodeStyle.BackColor = Color.Yellow;
tvwDirectorio.SelectedNodeStyle.ForeColor = Color.Red;
}
}
private void llenarNodos(TreeNode nodoPadre, IEnumerable<string> listaDirectorios)
{
foreach(string directorio in listaDirectorios)
{
TreeNode nodo = new TreeNode(Path.GetFileName(directorio));
nodoPadre.ChildNodes.Add(nodo);
IEnumerable<string> lista =
Directory.EnumerateDirectories(Path.Combine(Server.MapPath("../"),
nodo.ValuePath));
if(lista.Count() > 0) llenarNodos(nodo, lista);
}
}
protected void mostrarImagenesDirectorio(object sender, EventArgs e)
{
string directorio = Path.Combine(Server.MapPath("../"),
tvwDirectorio.SelectedNode.ValuePath.Replace(@"/", @"\"));
IEnumerable<string> archivos = Directory.EnumerateFiles(directorio, "*.jpg");
rptImagen.DataSource = archivos;
rptImagen.DataBind();
}
protected string obtenerUrl(string archivo)
{
return String.Format("../{0}/{1}",
tvwDirectorio.SelectedNode.ValuePath,Path.GetFileName(archivo));
}
protected string obtenerNombre(string archivo)
{
return Path.GetFileName(archivo);
}
}
}
Nota: Para leer directorios estamos usando Directory.EnumerateDirectories y para leer archivos estamos usando Directory.EnumerateFiles que es la forma mas eficiente de leer en .NET ya que solo crea un registro a la vez (consume menos memoria y es mas rápido).
Además se usa una función recursiva para llenar el TreeView con los directorios llamada "llenarNodos" que usa la propiedad ValuePath que obtiene la ruta del nodo actual.
También se definen 2 métodos protegidos: "obtenerUrl" y "obtenerNombre" que se usan en el HTML del Repeater.
Probar la Pagina Web
Guardar el Sitio Web, clic derecho a la Pagina "VisorImagenes.aspx" y seleccionar "Ver en el explorador". Se mostrará una ventana similar a la siguiente figura:
Observar como se muestra todas lar carpetas creadas dentro de la carpeta "Imagenes" en el TreeView, ahora seleccionar un directorio, por ejemplo "Empleados" y se mostrará las imágenes que esta contiene, similar a la siguiente figura:
Notar que al poner el mouse sobre una imagen se muestra como tooltip el nombre del archivo de imagen.
Ahora seleccionar otro directorio, por ejemplo "Bebidas" y disminuir el ancho del navegador (como si fuera una Tabla) y se muestra menos columnas pero el Diseño Web es Adaptativo (Responsive Web Design), tal como se ve en la siguiente figura:
Para finalizar, seleccionar otro directorio, por ejemplo "Condimentos" y disminuir aún mas el ancho del navegador (como si fuera un Teléfono Celular) y nuevamente el diseño se adapta mostrando una sola columna, tal como se ve en la siguiente figura:
Comentario Final
En este pequeño demo, hemos visto como llenar un TreeView en WebForms con los directorios de una cierta carpeta usando una función recursiva, además de como hacer el preview de su contenido usando un control Repeater y Plantillas de Datos con código incrustado en el servidor (las 2 funciones obtener). Además para mejorar la apariencia se hace usado hojas de estilo (CSS).
A los visitantes del Blog que no han sido alumnos míos y que a veces tienen pedidos que se hacen en clases en el programa PECI .NET o Web Developer, no es mi intención repetir lo que se ve en clases, sino, publicaríamos un Demo diario y el tiempo no me alcanzaría.
Saludos a todos y recuerden la frase: "Somos lo que pensamos de nosotros mismos".
Descarga
Etiquetas:
ASP.NET,
C#,
CSS,
Data Templates,
Demos,
Directory,
Enumerate,
Estilos,
Imágenes,
Jerarquía,
Lduenas,
Path,
Recursividad,
Repeater,
Responsive Web Design,
TreeNode,
TreeView,
ValuePath,
ViewState,
WebForms
El Libro del Día: Professional Sharepoint 2013 Development
El Libro del Día: 2014-11-28
Titulo: Professional Sharepoint 2013 Development
Autor: Reza Alirezaei, Brendon Schwartz, Matt Ranlett,
Scot Hillier, Brian Wilson, Jeff Fried, Paul Swider
Editorial: Wrox
Nro Paginas: 820
Capítulos:
CHAPTER 1 Architectural Overview of SharePoint 2013
CHAPTER 2 What’s New in SharePoint 2013
CHAPTER 3 Developer Tools for SharePoint 2013
CHAPTER 4 Application Lifecycle Management in SharePoint 2013
CHAPTER 5 Introducing Windows Azure and SharePoint 2013 Integration
CHAPTER 6 Getting Started with Developing Apps in SharePoint 2013
CHAPTER 7 Further Developing Apps in SharePoint 2013
CHAPTER 8 Developing Social Applications in SharePoint 2013
CHAPTER 9 Building Search-Based Applications in SharePoint 2013
CHAPTER 10 Web Content Management
CHAPTER 11 Using InfoPath with SharePoint 2013
CHAPTER 12 Enterprise Document Management
CHAPTER 13 Introducing Business Connectivity Services
CHAPTER 14 Advanced Business Connectivity Services
CHAPTER 15 Workflow Development in SharePoint 2013
CHAPTER 16 Integrating Reporting Services
CHAPTER 17 Developing Excel Applications in SharePoint 2013
CHAPTER 18 PerformancePoint Dashboards
CHAPTER 19 Developing Applications with Access
APPENDIX Additional Help and Resources
Descarga:
Professional_Sharepoint_2013_Development
Titulo: Professional Sharepoint 2013 Development
Autor: Reza Alirezaei, Brendon Schwartz, Matt Ranlett,
Scot Hillier, Brian Wilson, Jeff Fried, Paul Swider
Editorial: Wrox
Nro Paginas: 820
Capítulos:
CHAPTER 1 Architectural Overview of SharePoint 2013
CHAPTER 2 What’s New in SharePoint 2013
CHAPTER 3 Developer Tools for SharePoint 2013
CHAPTER 4 Application Lifecycle Management in SharePoint 2013
CHAPTER 5 Introducing Windows Azure and SharePoint 2013 Integration
CHAPTER 6 Getting Started with Developing Apps in SharePoint 2013
CHAPTER 7 Further Developing Apps in SharePoint 2013
CHAPTER 8 Developing Social Applications in SharePoint 2013
CHAPTER 9 Building Search-Based Applications in SharePoint 2013
CHAPTER 10 Web Content Management
CHAPTER 11 Using InfoPath with SharePoint 2013
CHAPTER 12 Enterprise Document Management
CHAPTER 13 Introducing Business Connectivity Services
CHAPTER 14 Advanced Business Connectivity Services
CHAPTER 15 Workflow Development in SharePoint 2013
CHAPTER 16 Integrating Reporting Services
CHAPTER 17 Developing Excel Applications in SharePoint 2013
CHAPTER 18 PerformancePoint Dashboards
CHAPTER 19 Developing Applications with Access
APPENDIX Additional Help and Resources
Descarga:
Professional_Sharepoint_2013_Development
Etiquetas:
ALM,
Architectural,
BCS,
Brendon Schwartz,
Developing Apps,
EDM,
Excel,
InfoPath,
Libros,
Matt Ranlett,
Reporting Services,
Reza Alirezaei,
Search,
SharePoint,
Social Apps,
Tools,
WCM,
Windows Azure,
Workflow,
Wrox
jueves, 27 de noviembre de 2014
El Libro del Día: Beginning Sharepoint 2013 Development
El Libro del Día: 2014-11-27
Titulo: Beginning Sharepoint 2013 Development
Autor: Steve Fox, Chris Johnson, Donovan Follette
Editorial: Wrox
Nro Paginas: 460
Capítulos:
PART I GETTING STARTED WITH SHAREPOINT 2013
CHAPTER 1 Introduction to SharePoint 2013
CHAPTER 2 Overview of the SharePoint 2013 App Model
CHAPTER 3 Developer Tooling for SharePoint 2013
CHAPTER 4 Understanding Your Development Options
CHAPTER 5 Overview of Windows Azure for SharePoint
PART II FUNDAMENTAL SHAREPOINT 2013 DEVELOPMENT BUILDING BLOCKS
CHAPTER 6 Developing, Integrating, and Building Applications in SharePoint 2013
CHAPTER 7 Packaging and Deploying SharePoint 2013 Apps
CHAPTER 8 Distributing SharePoint 2013 Apps
CHAPTER 9 Overview of the Client-Side Object Model and REST APIs
CHAPTER 10 Overview of OAuth in SharePoint 2013
PART III ADVANCED DEVELOPER TOPICS IN SHAREPOINT 2013
CHAPTER 11 Developing Integrated Apps for Office and SharePoint Solutions
CHAPTER 12 Remote Event Receivers in SharePoint 2013
CHAPTER 13 Building Line-of-Business Solutions Using Business Connectivity Services
CHAPTER 14 Developing Applications Using Office Services
CHAPTER 15 Developing Workflow Applications for SharePoint 2013
Descarga:
Beginning_Sharepoint_2013_Development
Titulo: Beginning Sharepoint 2013 Development
Autor: Steve Fox, Chris Johnson, Donovan Follette
Editorial: Wrox
Nro Paginas: 460
Capítulos:
PART I GETTING STARTED WITH SHAREPOINT 2013
CHAPTER 1 Introduction to SharePoint 2013
CHAPTER 2 Overview of the SharePoint 2013 App Model
CHAPTER 3 Developer Tooling for SharePoint 2013
CHAPTER 4 Understanding Your Development Options
CHAPTER 5 Overview of Windows Azure for SharePoint
PART II FUNDAMENTAL SHAREPOINT 2013 DEVELOPMENT BUILDING BLOCKS
CHAPTER 6 Developing, Integrating, and Building Applications in SharePoint 2013
CHAPTER 7 Packaging and Deploying SharePoint 2013 Apps
CHAPTER 8 Distributing SharePoint 2013 Apps
CHAPTER 9 Overview of the Client-Side Object Model and REST APIs
CHAPTER 10 Overview of OAuth in SharePoint 2013
PART III ADVANCED DEVELOPER TOPICS IN SHAREPOINT 2013
CHAPTER 11 Developing Integrated Apps for Office and SharePoint Solutions
CHAPTER 12 Remote Event Receivers in SharePoint 2013
CHAPTER 13 Building Line-of-Business Solutions Using Business Connectivity Services
CHAPTER 14 Developing Applications Using Office Services
CHAPTER 15 Developing Workflow Applications for SharePoint 2013
Descarga:
Beginning_Sharepoint_2013_Development
Etiquetas:
App Model,
Building,
Chris Johnson,
Deploying,
Distributing,
Donovan Follette,
Integrating,
Libros,
OAuth,
Office,
Options,
Packaging,
RER,
REST APIs,
SharePoint,
Steve Fox,
Tooling,
Windows Azure,
Workflow,
Wrox
miércoles, 26 de noviembre de 2014
Entrenamiento - Primera Charla .NET (HTE ACEE)
Primera Charla .NET (HTE ACEE)
Solo para recordar que el día Miércoles 3 de Diciembre iniciamos una serie de charlas orientadas a mejorar la calidad de las aplicaciones de todos los profesionales dedicados al Desarrollo de Software, en especial en Microsoft .NET.
Actualmente, la forma como la mayoría de profesionales desarrolla no es la mas adecuada, sin embargo es usada como un Estándar en la mayoría de Empresas, las razones pueden ser diversas: por costumbre, legado de conocimientos, facilidad y no como debería ser, que es por eficiencia: Performance (Menos Consumo de Procesador y Menos Memoria) y Escalabilidad (Concurrencia).
Es por eso que existen Frameworks de todo tipo, para "Facilitar" el trabajo del desarrollador y No para hacerlo mas eficiente, tales como:
- Acesso a Datos: SQL Helper, Enterprise Library, Application Blocks, LINQ, Entity Framework, MyBatis, NHibernate, etc.
- Interface de Usuario: Telerik, Kendo, Infragistics, Dev Express, Component One, etc
- JavaScript: jQuery, AJAX Control Toolkit, etc
- HTML, CSS: Bootstrap, jQuery UI, Node.js, Extend.js, YUI, etc.
Si bien es cierto, estos Frameworks ayudan a construir fácilmente la aplicación, pero, no es lo mas conveniente, ya que la mayoría son pesados, generan mucho código y no son totalmente personalizables; cuando es código propio uno tiene el control del desarrollo.
En esta serie de charlas se aprenderá las Mejores Practicas de Programación en cada tema, iniciando con .NET Framework, WinForms y ADO.NET en la primera charla. La segunda sera exclusiva para ASP.NET WebForm y MVC. Al siguiente año continuaremos con Programación Asíncrona, Reflection, MVC4, Web API, HTML5, Google Maps, You Tube, Drive, Polymer, Web Componentes, etc.
Solo falta una semana para la primera charla y ya quedan pocas vacantes. Los que no se han registrado, todavía tienen la oportunidad de pertenecer a un grupo diferente y selecto de personas que harán el cambio, la idea es formar una comunidad sólida y mejorar el nivel del desarrollo de software en el país.
Te esperamos.
Frase de Día: "La Suerte No existe, Lo que se logra, es producto del Esfuerzo".
Solo para recordar que el día Miércoles 3 de Diciembre iniciamos una serie de charlas orientadas a mejorar la calidad de las aplicaciones de todos los profesionales dedicados al Desarrollo de Software, en especial en Microsoft .NET.
Actualmente, la forma como la mayoría de profesionales desarrolla no es la mas adecuada, sin embargo es usada como un Estándar en la mayoría de Empresas, las razones pueden ser diversas: por costumbre, legado de conocimientos, facilidad y no como debería ser, que es por eficiencia: Performance (Menos Consumo de Procesador y Menos Memoria) y Escalabilidad (Concurrencia).
Es por eso que existen Frameworks de todo tipo, para "Facilitar" el trabajo del desarrollador y No para hacerlo mas eficiente, tales como:
- Acesso a Datos: SQL Helper, Enterprise Library, Application Blocks, LINQ, Entity Framework, MyBatis, NHibernate, etc.
- Interface de Usuario: Telerik, Kendo, Infragistics, Dev Express, Component One, etc
- JavaScript: jQuery, AJAX Control Toolkit, etc
- HTML, CSS: Bootstrap, jQuery UI, Node.js, Extend.js, YUI, etc.
Si bien es cierto, estos Frameworks ayudan a construir fácilmente la aplicación, pero, no es lo mas conveniente, ya que la mayoría son pesados, generan mucho código y no son totalmente personalizables; cuando es código propio uno tiene el control del desarrollo.
En esta serie de charlas se aprenderá las Mejores Practicas de Programación en cada tema, iniciando con .NET Framework, WinForms y ADO.NET en la primera charla. La segunda sera exclusiva para ASP.NET WebForm y MVC. Al siguiente año continuaremos con Programación Asíncrona, Reflection, MVC4, Web API, HTML5, Google Maps, You Tube, Drive, Polymer, Web Componentes, etc.
Solo falta una semana para la primera charla y ya quedan pocas vacantes. Los que no se han registrado, todavía tienen la oportunidad de pertenecer a un grupo diferente y selecto de personas que harán el cambio, la idea es formar una comunidad sólida y mejorar el nivel del desarrollo de software en el país.
Te esperamos.
Frase de Día: "La Suerte No existe, Lo que se logra, es producto del Esfuerzo".
Etiquetas:
.NET,
.NET Framework,
ADO.NET,
C#,
Charlas .NET,
Concurrencia,
Entrenamiento,
Escalabilidad,
HTE,
Lduenas,
Mejores Practicas,
Memoria,
Performance,
Procesador,
Seminarios,
WinForms
El Libro del Día: Pro SharePoint 2013 App Development
El Libro del Día: 2014-11-26
Titulo: Pro SharePoint 2013 App Development
Autor: Steve Wright
Editorial: Apress
Nro Paginas: 419
Capítulos:
Chapter 1: Introduction to SharePoint Apps
Chapter 2: Creating and Debugging Apps
Chapter 3: Managing the App Life Cycle
Chapter 4: Client-Side Logic with JavaScript
Chapter 5: Accessing the SharePoint Environment
Chapter 6: SharePoint App Security
Chapter 7: Web Services with REST and OData
Chapter 8: Business Connectivity Services
Chapter 9: App Logic Components
Chapter 10: Developing the User Experience
Chapter 11: Accessing SharePoint Search
Chapter 12: Using SharePoint’s Social Features
Chapter 13: Enhancing Apps with SharePoint Services
Chapter 14: Using Other App Environments
Descarga:
Pro_SharePoint_2013_App_Development
Titulo: Pro SharePoint 2013 App Development
Autor: Steve Wright
Editorial: Apress
Nro Paginas: 419
Capítulos:
Chapter 1: Introduction to SharePoint Apps
Chapter 2: Creating and Debugging Apps
Chapter 3: Managing the App Life Cycle
Chapter 4: Client-Side Logic with JavaScript
Chapter 5: Accessing the SharePoint Environment
Chapter 6: SharePoint App Security
Chapter 7: Web Services with REST and OData
Chapter 8: Business Connectivity Services
Chapter 9: App Logic Components
Chapter 10: Developing the User Experience
Chapter 11: Accessing SharePoint Search
Chapter 12: Using SharePoint’s Social Features
Chapter 13: Enhancing Apps with SharePoint Services
Chapter 14: Using Other App Environments
Descarga:
Pro_SharePoint_2013_App_Development
Etiquetas:
Apps,
Apress,
Components,
Creating,
Debugging,
Environment,
Javascript,
Libros,
Life Cycle,
Managing,
OData,
REST,
Search,
Security,
Services,
SharePoint,
Social,
Steve Wright,
Web Services
martes, 25 de noviembre de 2014
El Libro del Día: HTML5 Games Most Wanted
El Libro del Día: 2014-11-25
Titulo: HTML5 Games Most Wanted
Autor: Egor Kuryanovich, Shy Shalom, ...
Editorial: Friendsoft
Nro Paginas: 278
Capítulos:
Chapter 1: The State of Open Web Games
Chapter 2: Complexity from Simplicity
Chapter 3: How to Make Multi-Platform HTML5 Games from Scratch
Chapter 4: Creating, Saving, and Loading Tracks
Chapter 5: 3D CSS Tutorial
Chapter 6: Particle Systems
Chapter 7: Beginning WebGL
Chapter 8: CycleBlob: A WebGL Lightcycle Game
Chapter 9: A Real-Time Multiplayer Game Using WebSockets
Chapter 10: Hard-Pressed for a Choice of Technology
Descarga:
HTML5_Games_Most_Wanted
Titulo: HTML5 Games Most Wanted
Autor: Egor Kuryanovich, Shy Shalom, ...
Editorial: Friendsoft
Nro Paginas: 278
Capítulos:
Chapter 1: The State of Open Web Games
Chapter 2: Complexity from Simplicity
Chapter 3: How to Make Multi-Platform HTML5 Games from Scratch
Chapter 4: Creating, Saving, and Loading Tracks
Chapter 5: 3D CSS Tutorial
Chapter 6: Particle Systems
Chapter 7: Beginning WebGL
Chapter 8: CycleBlob: A WebGL Lightcycle Game
Chapter 9: A Real-Time Multiplayer Game Using WebSockets
Chapter 10: Hard-Pressed for a Choice of Technology
Descarga:
HTML5_Games_Most_Wanted
Etiquetas:
3D,
Creating,
CSS,
CycleBlob,
Egor Kuryanovich,
Friendsoft,
Games,
HTML5,
Libros,
Loading,
Multi-Platform,
Multiplayer,
Open Web,
Particle,
Real-time,
Saving,
Shy Shalom,
Tracks,
WebGL,
WebSockets
lunes, 24 de noviembre de 2014
El Libro del Día: Pro HTML5 Games
El Libro del Día: 2014-11-24
Titulo: Pro HTML5 Games
Autor: Aditya Ravi Shankar
Editorial: Apress
Nro Paginas: 357
Capítulos:
Chapter 1: HTML5 and JavaScript Essentials
Chapter 2: Creating a Basic Game World
Chapter 3: Physics Engine Basics
Chapter 4: Integrating The Physics Engine
Chapter 5: Creating the RTS Game World
Chapter 6: Adding Entities to Our World
Chapter 7: Intelligent Unit Movement
Chapter 8: Adding More Game Elements
Chapter 9: Adding Weapons and Combat
Chapter 10: Wrapping Up the Single-Player Campaign
Chapter 11: Multiplayer with WebSockets
Chapter 12: Multiplayer Gameplay
Descarga:
Pro_HTML5_Games
Titulo: Pro HTML5 Games
Autor: Aditya Ravi Shankar
Editorial: Apress
Nro Paginas: 357
Capítulos:
Chapter 1: HTML5 and JavaScript Essentials
Chapter 2: Creating a Basic Game World
Chapter 3: Physics Engine Basics
Chapter 4: Integrating The Physics Engine
Chapter 5: Creating the RTS Game World
Chapter 6: Adding Entities to Our World
Chapter 7: Intelligent Unit Movement
Chapter 8: Adding More Game Elements
Chapter 9: Adding Weapons and Combat
Chapter 10: Wrapping Up the Single-Player Campaign
Chapter 11: Multiplayer with WebSockets
Chapter 12: Multiplayer Gameplay
Descarga:
Pro_HTML5_Games
Etiquetas:
Aditya Ravi Shankar,
Apress,
Elements,
Engine,
Entities,
Gameplay,
Games,
HTML5,
Javascript,
Libros,
Movement,
Multiplayer,
Physics,
RTS,
Singleplayer,
Weapons,
WebSockets
domingo, 23 de noviembre de 2014
El Libro del Día: HTML & CSS. The Complete Reference
El Libro del Día: 2014-11-23
Titulo: HTML & CSS: The Complete Reference (5th Edition)
Autor: Thomas A. Powell
Editorial: McGraw Hill
Nro Paginas: 857
Capítulos:
Part I Core Markup
1 Traditional HTML and XHTML
2 Introducing HTML5
3 HTML and XHTML Element Reference
Part II Core Style
4 Introduction to CSS
5 CSS Syntax and Property Reference
6 CSS3 Proprietary and Emerging Features Reference
Part III Appendixes
A Character Entities
B Fonts
C Colors
D URLs
E Reading a Document Type Definition
Descarga:
HTML_CSS_The_Complete_Reference
Titulo: HTML & CSS: The Complete Reference (5th Edition)
Autor: Thomas A. Powell
Editorial: McGraw Hill
Nro Paginas: 857
Capítulos:
Part I Core Markup
1 Traditional HTML and XHTML
2 Introducing HTML5
3 HTML and XHTML Element Reference
Part II Core Style
4 Introduction to CSS
5 CSS Syntax and Property Reference
6 CSS3 Proprietary and Emerging Features Reference
Part III Appendixes
A Character Entities
B Fonts
C Colors
D URLs
E Reading a Document Type Definition
Descarga:
HTML_CSS_The_Complete_Reference
Etiquetas:
Characters,
Colors,
CSS,
CSS3,
DTD,
Elements,
Fonts,
HTML,
HTML5,
Libros,
McGraw Hill,
Property,
Reading,
Reference,
Style,
Syntax,
Thomas A. Powell,
URLs,
XHTML
sábado, 22 de noviembre de 2014
El Libro del Día: Hello! HTML5 & CSS3
El Libro del Día: 2014-11-22
Titulo: Hello! HTML5 & CSS3
Autor: Rob Crowther
Editorial: Manning
Nro Paginas: 561
Capítulos:
PART 1 LEARNING HTML5
1 Introducing HTML5 markup
2 HTML5 forms
3 Dynamic graphics
4 Audio and video
5 Browser-based APIs
6 Network and location APIs
PART 2 LEARNING CSS3
7 New CSS language features
8 Layout with CSS3
9 Motion and color
10 Borders and backgrounds with CSS3
11 Text and fonts
Descarga:
Hello_HTML5_CSS3
Titulo: Hello! HTML5 & CSS3
Autor: Rob Crowther
Editorial: Manning
Nro Paginas: 561
Capítulos:
PART 1 LEARNING HTML5
1 Introducing HTML5 markup
2 HTML5 forms
3 Dynamic graphics
4 Audio and video
5 Browser-based APIs
6 Network and location APIs
PART 2 LEARNING CSS3
7 New CSS language features
8 Layout with CSS3
9 Motion and color
10 Borders and backgrounds with CSS3
11 Text and fonts
Descarga:
Hello_HTML5_CSS3
viernes, 21 de noviembre de 2014
El Demo del Día: Filtrar y Ordenar en Cabeceras del DataGridView en WinForms
Filtrar y Ordenar en Cabeceras del DataGridView en WinForms
En este post aprenderemos como cambiar las cabeceras del control DataGridView de Windows Forms para incluir TextBoxs que permitan filtrar registros, así como etiquetas que permitan ordenar ascendente y descendentemente los datos de cada columna.
De repente muchos preguntaran porque tantos demos con Grillas y Cabeceras sobre estas, tanto en Windows y Web Forms y la respuesta es que este es el control mas usado y estas funcionalidades son muy usadas pero no es tan simple como configurar una propiedad y muchos eligen usar un control de terceros, pero con la ayuda de estos post aprenderás tu mismo a crearlos.
Requerimiento
Se necesita crear una consulta en Windows 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 poder ordenar cada columna en forma ascendente y descendente.
- Se debe mostrar el símbolo de ordenación: "▲" para ascendente y "▼" para descendente.
Solución
- Usaremos el control DataGridView y crearemos columnas personalizadas.
- Crearemos una clase DataGridViewTextBoxHeaderColumn para cada columna de tipo TextBox.
- Crearemos una clase DataGridViewTextBoxHeaderCell para la cabecera de cada columna, la cual contendrá un LinkLabel para ordenar y un TextBox para filtrar.
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 una Aplicación Windows Forms en C#
En Visual Studio crear un proyecto Windows Forms en C# con el nombre de "DataGridView_FiltroOrdenCabecera", luego cambiar el nombre del formulario a "frmConsultaProductos".
Arrastrar un DataGridView llamado "dgvProducto" y acoplarlo en todo el formulario, el diseño se mostrará similar a la siguiente figura:
Crear la Clase Entidad del Negocio
Crear la clase beProducto escribiendo el siguiente código:
using System;
namespace DataGridView_FiltroOrdenCabecera
{
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 DataGridView_FiltroOrdenCabecera
{
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 DataGridView_FiltroOrdenCabecera
{
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 una Clase para las Cabeceras de las Columnas del DataGridView
Crear la clase "DataGridViewTextBoxHeaderCell" escribiendo el siguiente código:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace DataGridView_FiltroOrdenCabecera
{
public class DataGridViewTextBoxHeaderCell : DataGridViewColumnHeaderCell
{
public TextBox txt;
public LinkLabel lbl;
public event EventHandler OrdenaCampo;
public event EventHandler CambiaTexto;
public DataGridViewTextBoxHeaderCell()
{
lbl = new LinkLabel();
lbl.Click += new EventHandler(ordenaCampo);
txt = new TextBox();
txt.TextChanged += new EventHandler(cambiaTexto);
}
protected override void Paint(Graphics graphics, Rectangle clipBounds,Rectangle cellBounds,
int rowIndex, DataGridViewElementStates dataGridViewElementState,
object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
lbl.Location = new Point(cellBounds.X + 2, cellBounds.Y+5);
lbl.Size = new Size(cellBounds.Size.Width - 4, 13);
lbl.BackColor = Color.Transparent;
lbl.Font=new Font("Arial",8,FontStyle.Bold);
lbl.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
txt.Location = new Point(cellBounds.X + 2,cellBounds.Y + 25);
txt.Size = new Size(cellBounds.Size.Width-4,20);
}
public string ValorEtiqueta
{
get
{
return (lbl.Text);
}
set
{
lbl.Text = value;
}
}
private void ordenaCampo(object sender, EventArgs e)
{
if (OrdenaCampo != null)
{
OrdenaCampo(this, e);
}
}
public string ValorTexto
{
get
{
return (txt.Text);
}
set
{
txt.Text = value;
}
}
private void cambiaTexto(object sender, EventArgs e)
{
if (CambiaTexto != null)
{
CambiaTexto(this, e);
}
}
}
}
Nota: La clase creada hereda de "DataGridViewColumnHeaderCell" y crea 2 controles: un LinkLabel "lbl" para ordenar y un TextBox "txt" para filtrar. Al "lbl" se le crea el evento "OrdenaCampo" y al "txt" se le crea el evento "CambiaTexto" para filtrar.
Además se crean 2 propiedades para exponer los valores de las etiquetas de las cabeceras: "ValorEtiqueta" y el valor de los textos: "ValorTexto".
Crear una Clase para las Columnas del DataGridView
Crear la clase "DataGridViewTextBoxHeaderColumn" escribiendo el siguiente código:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace DataGridView_FiltroOrdenCabecera
{
public class DataGridViewTextBoxHeaderColumn: DataGridViewTextBoxColumn
{
DataGridViewTextBoxHeaderCell textoCabecera = new DataGridViewTextBoxHeaderCell();
public DataGridViewTextBoxHeaderColumn()
{
this.CellTemplate = new DataGridViewTextBoxCell();
this.HeaderCell = textoCabecera;
}
protected override void OnDataGridViewChanged()
{
if (this.DataGridView != null)
{
this.DataGridView.Controls.Add(textoCabecera.lbl);
this.DataGridView.Controls.Add(textoCabecera.txt);
}
}
public DataGridViewTextBoxHeaderCell Texto
{
get
{
return this.textoCabecera;
}
}
}
}
Nota: La clase creada hereda de "DataGridViewTextBoxColumn" y crea un objeto "textoCabecera" de tipo "DataGridViewTextBoxHeaderCell" que se configura como propiedad "HeaderCell" de la columna. Este se expone como una propiedad llamada "Texto".
Además en el evento "OnDataGridViewChanged" se agrega los controles creados en la cabecera de la celda: el LinkLabel "lbl" y el TextBox "txt".
Usar las Clases creadas en el DataGridView del Formulario
Regresar al formulario "frmConsultaProductos" y escribir el siguiente código:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace DataGridView_FiltroOrdenCabecera
{
public partial class frmConsultaProductos : Form
{
private List<beProducto> lbeProducto;
private List<beProducto> lbeFiltro;
DataGridViewTextBoxHeaderColumn col1,col2,col3,col4,col5,col6;
public frmConsultaProductos()
{
InitializeComponent();
}
private void cargarProductos(object sender, EventArgs e)
{
brProducto obrProducto = new brProducto();
lbeProducto = obrProducto.listar();
dgvProducto.AutoGenerateColumns = false;
dgvProducto.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvProducto.ColumnHeadersHeight = 50;
dgvProducto.ColumnHeadersHeightSizeMode =
DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
lbeFiltro = lbeProducto;
dgvProducto.DataSource = lbeFiltro;
crearColumnasCabecera();
}
private void crearColumnasCabecera()
{
col1 = new DataGridViewTextBoxHeaderColumn();
col1.DataPropertyName = "IdProducto";
col1.Width = 70;
col1.Texto.ValorEtiqueta = "Código";
col1.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col1.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col1);
col2 = new DataGridViewTextBoxHeaderColumn();
col2.DataPropertyName = "Nombre";
col2.Width = 300;
col2.Texto.ValorEtiqueta = "Descripción del Producto";
col2.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col2.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col2);
col3 = new DataGridViewTextBoxHeaderColumn();
col3.DataPropertyName = "IdProveedor";
col3.Width = 70;
col3.Texto.ValorEtiqueta = "Id Prov";
col3.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col3.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col3);
col4 = new DataGridViewTextBoxHeaderColumn();
col4.DataPropertyName = "IdCategoria";
col4.Width = 70;
col4.Texto.ValorEtiqueta = "Id Cat";
col4.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col4.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col4);
col5 = new DataGridViewTextBoxHeaderColumn();
col5.DataPropertyName = "PrecioUnitario";
col5.Width = 70;
col5.Texto.ValorEtiqueta = "Pre Unit";
col5.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col5.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col5);
col6 = new DataGridViewTextBoxHeaderColumn();
col6.DataPropertyName = "Stock";
col6.Width = 70;
col6.Texto.ValorEtiqueta = "Stock";
col6.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col6.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col6);
}
private bool buscarProductos(beProducto obeProducto)
{
bool exitoIdProducto = true;
bool exitoNombre = true;
bool exitoIdProveedor = true;
bool exitoIdCategoria = true;
bool exitoPrecioUnitario = true;
bool exitoStock = true;
if (!col1.Texto.Equals("")) exitoIdProducto =
(obeProducto.IdProducto.ToString().Contains(col1.Texto.ValorTexto));
if (!col2.Texto.Equals("")) exitoNombre =
(obeProducto.Nombre.ToLower().Contains(col2.Texto.ValorTexto.ToLower()));
if (!col3.Texto.Equals("")) exitoIdProveedor =
(obeProducto.IdProveedor.ToString().Contains(col3.Texto.ValorTexto));
if (!col4.Texto.Equals("")) exitoIdCategoria =
(obeProducto.IdCategoria.ToString().Contains(col4.Texto.ValorTexto));
if (!col5.Texto.Equals("")) exitoPrecioUnitario =
(obeProducto.PrecioUnitario.ToString().Contains(col5.Texto.ValorTexto));
if (!col6.Texto.Equals("")) exitoStock =
(obeProducto.Stock.ToString().Contains(col6.Texto.ValorTexto));
return (exitoIdProducto && exitoNombre && exitoIdProveedor && exitoIdCategoria
&& exitoPrecioUnitario && exitoStock);
}
protected void filtrarProductos(object sender, EventArgs e)
{
Predicate<beProducto> pred = new Predicate<beProducto>(buscarProductos);
lbeFiltro = lbeProducto.FindAll(pred);
dgvProducto.DataSource = lbeFiltro;
}
protected void ordenarProductos(object sender, EventArgs e)
{
DataGridViewTextBoxHeaderCell cabecera = (DataGridViewTextBoxHeaderCell)sender;
DataGridViewTextBoxHeaderColumn columna =
(DataGridViewTextBoxHeaderColumn )cabecera.OwningColumn;
string campo = columna.DataPropertyName;
string etiqueta = cabecera.ValorEtiqueta.Replace("▲","").Replace("▼","").Trim();
int n = 0;
string simbolo = "▲";
if (columna.Tag != null)
{
if (columna.Tag.Equals(0))
{
simbolo = "▼";
n = 1;
}
}
columna.Tag = n;
cabecera.ValorEtiqueta = String.Format("{0} {1}", etiqueta, simbolo);
if(n.Equals(0)) lbeFiltro = lbeFiltro.OrderBy(x=>x.GetType().
GetProperty(campo).GetValue(x,null)).ToList();
else lbeFiltro = lbeFiltro.OrderByDescending(x => x.GetType().
GetProperty(campo).GetValue(x, null)).ToList();
dgvProducto.DataSource = lbeFiltro;
}
}
}
En el evento "OrdenaCampo" de la cabecera de cada columna se asocia la función "ordenarProductos" y en el evento "CambiaTexto" se asocia a la función "filtrarProductos".
Modificar el archivo App.Config para incluir la Cadena de Conexión
<?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>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
Probar la Aplicación Windows Forms
Grabar la aplicación y ejecutarla con F5. Se mostrará la siguiente ventana:
En las cabeceras de cada columna aparecen unos LinkLabels y TextBoxs, probamos la ordenación dando clic a los LinkLabel y la primera vez se ordenará en forma ascendente y la siguiente en forma descendente apareciendo su respectivo símbolo, tal como se muestra en la siguiente figura:
Escribir en la cabecera del código el "1" y en la del nombre "ma" y cada vez que se escribe se realiza el filtro desconectado, tal como se muestra a continuación:
Comentario Final
En este post hemos aprendido como sobre escribir las clases "DataGridViewColumnHeaderCell" y "DataGridViewTextBoxColumn" para crear columnas con cabeceras personalizadas que contengan controles: LinkLabels para ordenar y TextBox para filtrar.
En Windows Forms crear cabeceras en el DataGridView es un poco mas trabajoso que en ASP.NET WebForms y MVC que usan plantillas y que en WPF que usa estilos y es mas fácil personalizar.
Pero de todas formas no es imposible y lo mejor es que puedes hacer los cambios que deseas ya que tienes el fuente del código. Espero les sirva a todos los visitantes del Blog.
Creo que después de este buen Demo algunos se animarán a ir al Seminario de Buenas Prácticas en .NET, sobre todo los que nunca han llevado cursos conmigo.
Descarga
Demo26_DataGridView_FiltroOrdenCabecera
En este post aprenderemos como cambiar las cabeceras del control DataGridView de Windows Forms para incluir TextBoxs que permitan filtrar registros, así como etiquetas que permitan ordenar ascendente y descendentemente los datos de cada columna.
De repente muchos preguntaran porque tantos demos con Grillas y Cabeceras sobre estas, tanto en Windows y Web Forms y la respuesta es que este es el control mas usado y estas funcionalidades son muy usadas pero no es tan simple como configurar una propiedad y muchos eligen usar un control de terceros, pero con la ayuda de estos post aprenderás tu mismo a crearlos.
Requerimiento
Se necesita crear una consulta en Windows 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 poder ordenar cada columna en forma ascendente y descendente.
- Se debe mostrar el símbolo de ordenación: "▲" para ascendente y "▼" para descendente.
Solución
- Usaremos el control DataGridView y crearemos columnas personalizadas.
- Crearemos una clase DataGridViewTextBoxHeaderColumn para cada columna de tipo TextBox.
- Crearemos una clase DataGridViewTextBoxHeaderCell para la cabecera de cada columna, la cual contendrá un LinkLabel para ordenar y un TextBox para filtrar.
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 una Aplicación Windows Forms en C#
En Visual Studio crear un proyecto Windows Forms en C# con el nombre de "DataGridView_FiltroOrdenCabecera", luego cambiar el nombre del formulario a "frmConsultaProductos".
Arrastrar un DataGridView llamado "dgvProducto" y acoplarlo en todo el formulario, el diseño se mostrará similar a la siguiente figura:
Crear la Clase Entidad del Negocio
Crear la clase beProducto escribiendo el siguiente código:
using System;
namespace DataGridView_FiltroOrdenCabecera
{
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 DataGridView_FiltroOrdenCabecera
{
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 DataGridView_FiltroOrdenCabecera
{
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 una Clase para las Cabeceras de las Columnas del DataGridView
Crear la clase "DataGridViewTextBoxHeaderCell" escribiendo el siguiente código:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace DataGridView_FiltroOrdenCabecera
{
public class DataGridViewTextBoxHeaderCell : DataGridViewColumnHeaderCell
{
public TextBox txt;
public LinkLabel lbl;
public event EventHandler OrdenaCampo;
public event EventHandler CambiaTexto;
public DataGridViewTextBoxHeaderCell()
{
lbl = new LinkLabel();
lbl.Click += new EventHandler(ordenaCampo);
txt = new TextBox();
txt.TextChanged += new EventHandler(cambiaTexto);
}
protected override void Paint(Graphics graphics, Rectangle clipBounds,Rectangle cellBounds,
int rowIndex, DataGridViewElementStates dataGridViewElementState,
object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, dataGridViewElementState,
value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
lbl.Location = new Point(cellBounds.X + 2, cellBounds.Y+5);
lbl.Size = new Size(cellBounds.Size.Width - 4, 13);
lbl.BackColor = Color.Transparent;
lbl.Font=new Font("Arial",8,FontStyle.Bold);
lbl.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
txt.Location = new Point(cellBounds.X + 2,cellBounds.Y + 25);
txt.Size = new Size(cellBounds.Size.Width-4,20);
}
public string ValorEtiqueta
{
get
{
return (lbl.Text);
}
set
{
lbl.Text = value;
}
}
private void ordenaCampo(object sender, EventArgs e)
{
if (OrdenaCampo != null)
{
OrdenaCampo(this, e);
}
}
public string ValorTexto
{
get
{
return (txt.Text);
}
set
{
txt.Text = value;
}
}
private void cambiaTexto(object sender, EventArgs e)
{
if (CambiaTexto != null)
{
CambiaTexto(this, e);
}
}
}
}
Nota: La clase creada hereda de "DataGridViewColumnHeaderCell" y crea 2 controles: un LinkLabel "lbl" para ordenar y un TextBox "txt" para filtrar. Al "lbl" se le crea el evento "OrdenaCampo" y al "txt" se le crea el evento "CambiaTexto" para filtrar.
Además se crean 2 propiedades para exponer los valores de las etiquetas de las cabeceras: "ValorEtiqueta" y el valor de los textos: "ValorTexto".
Crear una Clase para las Columnas del DataGridView
Crear la clase "DataGridViewTextBoxHeaderColumn" escribiendo el siguiente código:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace DataGridView_FiltroOrdenCabecera
{
public class DataGridViewTextBoxHeaderColumn: DataGridViewTextBoxColumn
{
DataGridViewTextBoxHeaderCell textoCabecera = new DataGridViewTextBoxHeaderCell();
public DataGridViewTextBoxHeaderColumn()
{
this.CellTemplate = new DataGridViewTextBoxCell();
this.HeaderCell = textoCabecera;
}
protected override void OnDataGridViewChanged()
{
if (this.DataGridView != null)
{
this.DataGridView.Controls.Add(textoCabecera.lbl);
this.DataGridView.Controls.Add(textoCabecera.txt);
}
}
public DataGridViewTextBoxHeaderCell Texto
{
get
{
return this.textoCabecera;
}
}
}
}
Nota: La clase creada hereda de "DataGridViewTextBoxColumn" y crea un objeto "textoCabecera" de tipo "DataGridViewTextBoxHeaderCell" que se configura como propiedad "HeaderCell" de la columna. Este se expone como una propiedad llamada "Texto".
Además en el evento "OnDataGridViewChanged" se agrega los controles creados en la cabecera de la celda: el LinkLabel "lbl" y el TextBox "txt".
Usar las Clases creadas en el DataGridView del Formulario
Regresar al formulario "frmConsultaProductos" y escribir el siguiente código:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace DataGridView_FiltroOrdenCabecera
{
public partial class frmConsultaProductos : Form
{
private List<beProducto> lbeProducto;
private List<beProducto> lbeFiltro;
DataGridViewTextBoxHeaderColumn col1,col2,col3,col4,col5,col6;
public frmConsultaProductos()
{
InitializeComponent();
}
private void cargarProductos(object sender, EventArgs e)
{
brProducto obrProducto = new brProducto();
lbeProducto = obrProducto.listar();
dgvProducto.AutoGenerateColumns = false;
dgvProducto.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgvProducto.ColumnHeadersHeight = 50;
dgvProducto.ColumnHeadersHeightSizeMode =
DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
lbeFiltro = lbeProducto;
dgvProducto.DataSource = lbeFiltro;
crearColumnasCabecera();
}
private void crearColumnasCabecera()
{
col1 = new DataGridViewTextBoxHeaderColumn();
col1.DataPropertyName = "IdProducto";
col1.Width = 70;
col1.Texto.ValorEtiqueta = "Código";
col1.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col1.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col1);
col2 = new DataGridViewTextBoxHeaderColumn();
col2.DataPropertyName = "Nombre";
col2.Width = 300;
col2.Texto.ValorEtiqueta = "Descripción del Producto";
col2.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col2.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col2);
col3 = new DataGridViewTextBoxHeaderColumn();
col3.DataPropertyName = "IdProveedor";
col3.Width = 70;
col3.Texto.ValorEtiqueta = "Id Prov";
col3.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col3.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col3);
col4 = new DataGridViewTextBoxHeaderColumn();
col4.DataPropertyName = "IdCategoria";
col4.Width = 70;
col4.Texto.ValorEtiqueta = "Id Cat";
col4.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col4.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col4);
col5 = new DataGridViewTextBoxHeaderColumn();
col5.DataPropertyName = "PrecioUnitario";
col5.Width = 70;
col5.Texto.ValorEtiqueta = "Pre Unit";
col5.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col5.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col5);
col6 = new DataGridViewTextBoxHeaderColumn();
col6.DataPropertyName = "Stock";
col6.Width = 70;
col6.Texto.ValorEtiqueta = "Stock";
col6.Texto.OrdenaCampo += new EventHandler(ordenarProductos);
col6.Texto.CambiaTexto += new EventHandler(filtrarProductos);
dgvProducto.Columns.Add(col6);
}
private bool buscarProductos(beProducto obeProducto)
{
bool exitoIdProducto = true;
bool exitoNombre = true;
bool exitoIdProveedor = true;
bool exitoIdCategoria = true;
bool exitoPrecioUnitario = true;
bool exitoStock = true;
if (!col1.Texto.Equals("")) exitoIdProducto =
(obeProducto.IdProducto.ToString().Contains(col1.Texto.ValorTexto));
if (!col2.Texto.Equals("")) exitoNombre =
(obeProducto.Nombre.ToLower().Contains(col2.Texto.ValorTexto.ToLower()));
if (!col3.Texto.Equals("")) exitoIdProveedor =
(obeProducto.IdProveedor.ToString().Contains(col3.Texto.ValorTexto));
if (!col4.Texto.Equals("")) exitoIdCategoria =
(obeProducto.IdCategoria.ToString().Contains(col4.Texto.ValorTexto));
if (!col5.Texto.Equals("")) exitoPrecioUnitario =
(obeProducto.PrecioUnitario.ToString().Contains(col5.Texto.ValorTexto));
if (!col6.Texto.Equals("")) exitoStock =
(obeProducto.Stock.ToString().Contains(col6.Texto.ValorTexto));
return (exitoIdProducto && exitoNombre && exitoIdProveedor && exitoIdCategoria
&& exitoPrecioUnitario && exitoStock);
}
protected void filtrarProductos(object sender, EventArgs e)
{
Predicate<beProducto> pred = new Predicate<beProducto>(buscarProductos);
lbeFiltro = lbeProducto.FindAll(pred);
dgvProducto.DataSource = lbeFiltro;
}
protected void ordenarProductos(object sender, EventArgs e)
{
DataGridViewTextBoxHeaderCell cabecera = (DataGridViewTextBoxHeaderCell)sender;
DataGridViewTextBoxHeaderColumn columna =
(DataGridViewTextBoxHeaderColumn )cabecera.OwningColumn;
string campo = columna.DataPropertyName;
string etiqueta = cabecera.ValorEtiqueta.Replace("▲","").Replace("▼","").Trim();
int n = 0;
string simbolo = "▲";
if (columna.Tag != null)
{
if (columna.Tag.Equals(0))
{
simbolo = "▼";
n = 1;
}
}
columna.Tag = n;
cabecera.ValorEtiqueta = String.Format("{0} {1}", etiqueta, simbolo);
if(n.Equals(0)) lbeFiltro = lbeFiltro.OrderBy(x=>x.GetType().
GetProperty(campo).GetValue(x,null)).ToList();
else lbeFiltro = lbeFiltro.OrderByDescending(x => x.GetType().
GetProperty(campo).GetValue(x, null)).ToList();
dgvProducto.DataSource = lbeFiltro;
}
}
}
Nota: En el evento "load" del formulario se llama a la función controladora "cargarProductos" que obtiene los datos y configura el DataGridView "dgvProducto" sobre todo creando las columnas personalizadas en la función "crearColumnasCabecera".
En el evento "OrdenaCampo" de la cabecera de cada columna se asocia la función "ordenarProductos" y en el evento "CambiaTexto" se asocia a la función "filtrarProductos".
Modificar el archivo App.Config para incluir la Cadena de Conexión
<?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>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
Probar la Aplicación Windows Forms
Grabar la aplicación y ejecutarla con F5. Se mostrará la siguiente ventana:
En las cabeceras de cada columna aparecen unos LinkLabels y TextBoxs, probamos la ordenación dando clic a los LinkLabel y la primera vez se ordenará en forma ascendente y la siguiente en forma descendente apareciendo su respectivo símbolo, tal como se muestra en la siguiente figura:
Escribir en la cabecera del código el "1" y en la del nombre "ma" y cada vez que se escribe se realiza el filtro desconectado, tal como se muestra a continuación:
Comentario Final
En este post hemos aprendido como sobre escribir las clases "DataGridViewColumnHeaderCell" y "DataGridViewTextBoxColumn" para crear columnas con cabeceras personalizadas que contengan controles: LinkLabels para ordenar y TextBox para filtrar.
En Windows Forms crear cabeceras en el DataGridView es un poco mas trabajoso que en ASP.NET WebForms y MVC que usan plantillas y que en WPF que usa estilos y es mas fácil personalizar.
Pero de todas formas no es imposible y lo mejor es que puedes hacer los cambios que deseas ya que tienes el fuente del código. Espero les sirva a todos los visitantes del Blog.
Creo que después de este buen Demo algunos se animarán a ir al Seminario de Buenas Prácticas en .NET, sobre todo los que nunca han llevado cursos conmigo.
Descarga
Demo26_DataGridView_FiltroOrdenCabecera
Etiquetas:
C#,
Cabeceras,
DataGridView,
DataGridViewColumnHeaderCell,
DataGridViewTextBoxColumn,
DataPropertyName,
Demos,
Filtrar,
Lduenas,
Listas Objetos,
Ordenar,
OrderBy,
OwningColumn,
Reflection,
Windows Forms,
WinForms
El Libro del Día: Start Here! Learn HTML5
El Libro del Día: 2014-11-21
Titulo: Start Here! Learn HTML5
Autor: Faithe Wempen
Editorial: Microsoft
Nro Paginas: 360
Capítulos:
Part I Getting Started with HTML
Chapter 1 HTML Basics: The Least You Need to Know
Chapter 2 Setting Up the Document Structure
Chapter 3 Formatting Text with Tags
Chapter 4 Using Lists and Backgrounds
Chapter 5 Creating Hyperlinks and Anchors
Part II Style Sheets and Graphics
Chapter 6 Introduction to Style Sheets
Chapter 7 Formatting Text with CSS
Chapter 8 Formatting Paragraphs with CSS
Chapter 9 Inserting Graphics
Part III Page Layout and Navigation
Chapter 10 Creating Navigational Aids
Chapter 11 Creating Division-Based Layouts
Chapter 12 Creating Tables
Chapter 13 Formatting Tables
Chapter 14 Creating User Forms
Chapter 15 Incorporating Sound and Video
Chapter 16 HTML and Microsoft Expression Web
Part IV Appendices
Appendix A Designing for Usability
Appendix B Designing for Accessibility
Appendix C Quick Reference
Descarga:
Start_Here_Learn_HTML5
Titulo: Start Here! Learn HTML5
Autor: Faithe Wempen
Editorial: Microsoft
Nro Paginas: 360
Capítulos:
Part I Getting Started with HTML
Chapter 1 HTML Basics: The Least You Need to Know
Chapter 2 Setting Up the Document Structure
Chapter 3 Formatting Text with Tags
Chapter 4 Using Lists and Backgrounds
Chapter 5 Creating Hyperlinks and Anchors
Part II Style Sheets and Graphics
Chapter 6 Introduction to Style Sheets
Chapter 7 Formatting Text with CSS
Chapter 8 Formatting Paragraphs with CSS
Chapter 9 Inserting Graphics
Part III Page Layout and Navigation
Chapter 10 Creating Navigational Aids
Chapter 11 Creating Division-Based Layouts
Chapter 12 Creating Tables
Chapter 13 Formatting Tables
Chapter 14 Creating User Forms
Chapter 15 Incorporating Sound and Video
Chapter 16 HTML and Microsoft Expression Web
Part IV Appendices
Appendix A Designing for Usability
Appendix B Designing for Accessibility
Appendix C Quick Reference
Descarga:
Start_Here_Learn_HTML5
Etiquetas:
Anchors,
Backgrounds,
CSS,
Faithe Wempen,
Forms,
Graphics,
HTML5,
Hyperlinks,
Layouts,
Libros,
Lists,
Microsoft,
Navigation,
Sound,
Structure,
Style Sheets,
Tables,
Tags,
Video
jueves, 20 de noviembre de 2014
El Libro del Día: Building Web Applications with SVG
El Libro del Día: 2014-11-20
Titulo: Building Web Applications with SVG
Autor: David Dailey, Jon Frost, Domenico Strazzullo
Editorial: Microsoft
Nro Paginas: 293
Capítulos:
Chapter 1 SVG Basics
Chapter 2 Creating and Editing SVG Graphics
Chapter 3 Adding Text, Style, and Transforms
Chapter 4 Motion and Interactivity
Chapter 5 SVG Filters
Chapter 6 SVG Tools and Resources
Chapter 7 Building a Web Application: Case Studies
Descarga:
Building_Web_Applications_with_SVG
Titulo: Building Web Applications with SVG
Autor: David Dailey, Jon Frost, Domenico Strazzullo
Editorial: Microsoft
Nro Paginas: 293
Capítulos:
Chapter 1 SVG Basics
Chapter 2 Creating and Editing SVG Graphics
Chapter 3 Adding Text, Style, and Transforms
Chapter 4 Motion and Interactivity
Chapter 5 SVG Filters
Chapter 6 SVG Tools and Resources
Chapter 7 Building a Web Application: Case Studies
Descarga:
Building_Web_Applications_with_SVG
Etiquetas:
Basics,
Case Studies,
David Dailey,
Domenico Strazzullo,
Filters,
Graphics,
HTML5,
Interactivity,
Jon Frost,
Libros,
Microsoft,
Motion,
Resources,
Style,
SVG,
Text,
Tools,
Transforms,
Web Applications
miércoles, 19 de noviembre de 2014
El Libro del Día: HTML5 Programming for ASP.NET Developers
El Libro del Día: 2014-11-19
Titulo: HTML5 Programming for ASP.NET Developers
Autor: Bipin Joshi
Editorial: Apress
Nro Paginas: 379
Capítulos:
Chapter 1: Overview of HTML5 and ASP.NET 4.5
Chapter 2: Overview of jQuery
Chapter 3: Working with Audio and Video
Chapter 4: Drawing with the Canvas
Chapter 5: Working with Forms and Controls
Chapter 6: Using History API and Custom Data Attributes
Chapter 7: Storing Data in Web Storage
Chapter 8: Developing Offline Web Applications
Chapter 9: Dealing with Local Files Using the File API
Chapter 10: Multithreading in Web Pages Using Web Workers
Chapter 11: Using the Communication API and Web Sockets
Chapter 12: Finding Location with the Geolocation API
Chapter 13: Styling Web Forms and Views with CSS3
Appendix A: HTML5 Learning Resources
Descarga:
HTML5_Programming_ASPNET_Developers
Titulo: HTML5 Programming for ASP.NET Developers
Autor: Bipin Joshi
Editorial: Apress
Nro Paginas: 379
Capítulos:
Chapter 1: Overview of HTML5 and ASP.NET 4.5
Chapter 2: Overview of jQuery
Chapter 3: Working with Audio and Video
Chapter 4: Drawing with the Canvas
Chapter 5: Working with Forms and Controls
Chapter 6: Using History API and Custom Data Attributes
Chapter 7: Storing Data in Web Storage
Chapter 8: Developing Offline Web Applications
Chapter 9: Dealing with Local Files Using the File API
Chapter 10: Multithreading in Web Pages Using Web Workers
Chapter 11: Using the Communication API and Web Sockets
Chapter 12: Finding Location with the Geolocation API
Chapter 13: Styling Web Forms and Views with CSS3
Appendix A: HTML5 Learning Resources
Descarga:
HTML5_Programming_ASPNET_Developers
Etiquetas:
Apress,
ASP.NET,
Audio,
Bipin Joshi,
Canvas,
Controls,
CSS3,
Custom Data,
File API,
Forms,
Geolocation,
History API,
HTML5,
jQuery,
Libros,
Offline,
Video,
Web Sockets,
Web Storage,
Web Workers
martes, 18 de noviembre de 2014
El Libro del Día: Pro HTML5 Performance
El Libro del Día: 2014-11-18
Titulo: Pro HTML5 Performance
Autor: Jay Bryant, Mike Jones
Editorial: Apress
Nro Paginas: 285
Capítulos:
Part 1: Introduction
Chapter 1: Introduction
Part 2: Performance Basics
Chapter 2: Development Principles
Chapter 3: Performance Guidelines
Chapter 4: Responsive Web Design
Chapter 5: Understanding the Web Reuse Pattern
Part 3: Building a Web Site
Chapter 6: Page Template
Chapter 7: Navigation
Chapter 8: Masthead
Chapter 9: Footer
Chapter 10: Fractal Design Patterns
Chapter 11: Link Control
Chapter 12: Sidebox Control
Chapter 13: Button Control
Chapter 14: Price Control
Chapter 15: Product Control
Chapter 16: Table Control
Chapter 17: Tab Control
Chapter 18: Form Controls
Descarga:
Pro_HTML5_Performance
Titulo: Pro HTML5 Performance
Autor: Jay Bryant, Mike Jones
Editorial: Apress
Nro Paginas: 285
Capítulos:
Part 1: Introduction
Chapter 1: Introduction
Part 2: Performance Basics
Chapter 2: Development Principles
Chapter 3: Performance Guidelines
Chapter 4: Responsive Web Design
Chapter 5: Understanding the Web Reuse Pattern
Part 3: Building a Web Site
Chapter 6: Page Template
Chapter 7: Navigation
Chapter 8: Masthead
Chapter 9: Footer
Chapter 10: Fractal Design Patterns
Chapter 11: Link Control
Chapter 12: Sidebox Control
Chapter 13: Button Control
Chapter 14: Price Control
Chapter 15: Product Control
Chapter 16: Table Control
Chapter 17: Tab Control
Chapter 18: Form Controls
Descarga:
Pro_HTML5_Performance
Etiquetas:
Apress,
Button,
Footer,
Fractal,
HTML5,
Jay Bryant,
Libros,
Link,
Masthead,
Mike Jones,
Navigation,
Page Template,
Performance,
Price,
Product,
Responsive,
Sidebox,
Tab,
Table,
Web Reuse
lunes, 17 de noviembre de 2014
El Libro del Día:Practical WPF Charts and Graphics
El Libro del Día: 2014-11-17
Titulo: Practical WPF Charts and Graphics
Autor: Jack Xu
Editorial: Apress
Nro Paginas: 709
Capítulos:
1. Overview of WPF Programming
2. 2D Transformations
3. WPF Graphics Basics in 2D
4. Colors and Brushes
5. 2D Line charts
6. Specialized 2D Charts
7. Stock Charts
8. Interactive 2D Charts
9. 2D Chart Controls
10. Data Interpolations
11. Curve Fitting
12. 3D Transformations
13. WPF Graphics Basics in 3D
14. 3D Charts with the WPF 3D Engine
15. 3D Charts Without the WPF 3D Engine
16. Specialized 3D Charts
Descarga:
Practical_WPF_Charts_Graphics
Titulo: Practical WPF Charts and Graphics
Autor: Jack Xu
Editorial: Apress
Nro Paginas: 709
Capítulos:
1. Overview of WPF Programming
2. 2D Transformations
3. WPF Graphics Basics in 2D
4. Colors and Brushes
5. 2D Line charts
6. Specialized 2D Charts
7. Stock Charts
8. Interactive 2D Charts
9. 2D Chart Controls
10. Data Interpolations
11. Curve Fitting
12. 3D Transformations
13. WPF Graphics Basics in 3D
14. 3D Charts with the WPF 3D Engine
15. 3D Charts Without the WPF 3D Engine
16. Specialized 3D Charts
Descarga:
Practical_WPF_Charts_Graphics
Etiquetas:
2D,
3D,
3D Charts,
3D Engine,
Apress,
Brushes,
Charts,
Colors,
Controls,
Curve,
Graphics,
Interactive,
Interpolations,
Jack Xu,
Libros,
Lines,
Specialized,
Stock,
Transformations,
WPF
domingo, 16 de noviembre de 2014
El Libro del Día: Building Enterprise Applications with WPF and The MVVM Pattern
El Libro del Día: 2014-11-16
Titulo: Building Enterprise Applications with WPF and The MVVM Pattern
Autor: Raffaele Garofalo
Editorial: Microsoft
Nro Paginas: 225
Capítulos:
1 Introduction to Model View ViewModel and Line of Business Applications
2 Design Patterns
3 The Domain Model
4 The Data Access Layer
5 The Business Layer
6 The UI Layer with MVVM
7 MVVM Frameworks and Toolkits
Descarga:
Building_Enterprise_Applications_with_WPF_and_The_MVVM_Pattern
Titulo: Building Enterprise Applications with WPF and The MVVM Pattern
Autor: Raffaele Garofalo
Editorial: Microsoft
Nro Paginas: 225
Capítulos:
1 Introduction to Model View ViewModel and Line of Business Applications
2 Design Patterns
3 The Domain Model
4 The Data Access Layer
5 The Business Layer
6 The UI Layer with MVVM
7 MVVM Frameworks and Toolkits
Descarga:
Building_Enterprise_Applications_with_WPF_and_The_MVVM_Pattern
Etiquetas:
Business Applications,
Business Layer,
Data Access Layer,
Design Patterns,
Domain Model,
Frameworks,
Libros,
Microsoft,
MVVM,
Raffaele Garofalo,
Toolkits,
UI Layer,
WPF
sábado, 15 de noviembre de 2014
El Libro del Día: XAML Developer Reference
El Libro del Día: 2014-11-15
Titulo: XAML Developer Reference
Autor: Mamta Dalal, Ashish Ghoda
Editorial: Microsoft
Nro Paginas: 342
Capítulos:
Part I XAML Basics
Chapter 1 Introducing XAML
Chapter 2 Object Elements and Attributes
Chapter 3 XAML Properties and Events
Part II Enhancing User Experience
Chapter 4 Markup Extensions and Other Features
Chapter 5 Resources, Styles, and Triggers
Part III XAML User Interface Controls
Chapter 6 Layout and Positioning System
Chapter 7 Form and Functional Controls
Part IV Content Integration and Animation
Chapter 8 Data Binding
Chapter 9 Media, Graphics, and Animation
Part V Appendixes
Appendix A Major Namespaces and Classes
Appendix B XAML Editors and Tools
Descarga:
XAML_Developer_Reference
Titulo: XAML Developer Reference
Autor: Mamta Dalal, Ashish Ghoda
Editorial: Microsoft
Nro Paginas: 342
Capítulos:
Part I XAML Basics
Chapter 1 Introducing XAML
Chapter 2 Object Elements and Attributes
Chapter 3 XAML Properties and Events
Part II Enhancing User Experience
Chapter 4 Markup Extensions and Other Features
Chapter 5 Resources, Styles, and Triggers
Part III XAML User Interface Controls
Chapter 6 Layout and Positioning System
Chapter 7 Form and Functional Controls
Part IV Content Integration and Animation
Chapter 8 Data Binding
Chapter 9 Media, Graphics, and Animation
Part V Appendixes
Appendix A Major Namespaces and Classes
Appendix B XAML Editors and Tools
Descarga:
XAML_Developer_Reference
Etiquetas:
Animation,
Ashish Ghoda,
Attributes,
Data Binding,
Elements,
Events,
Extensions,
Graphics,
Layout,
Libros,
Mamta Dalal,
Media,
Microsoft,
Properties,
Reference,
Resources,
Styles,
Tools,
Triggers,
XAML
viernes, 14 de noviembre de 2014
El Libro del Día: Professional WPF Programming
El Libro del Día: 2014-11-14
Titulo: Professional WPF Programming
Autor: Chris Andrade, Shawn Livermore, Mike Meyers, Scott Van Vliet
Editorial: Wrox
Nro Paginas: 482
Capítulos:
Chapter 1: Overview of Windows Presentation Foundation
Chapter 2: WPF and .NET Programming
Chapter 3: Anatomy of a WPF-Enabled Application
Chapter 4: Building a Rich UI with Microsoft Expression Blend - Part I
Chapter 5: Building a Rich UI with Microsoft Expression Blend - Part II
Chapter 6: Special Effects
Chapter 7: Custom Controls
Chapter 8: Using WPF in the Enterprise
Chapter 9: Security
Chapter 10: WPF and Win32 Interop
Chapter 11: Advanced Development Concepts
Descarga:
Professional_WPF_Programming
Titulo: Professional WPF Programming
Autor: Chris Andrade, Shawn Livermore, Mike Meyers, Scott Van Vliet
Editorial: Wrox
Nro Paginas: 482
Capítulos:
Chapter 1: Overview of Windows Presentation Foundation
Chapter 2: WPF and .NET Programming
Chapter 3: Anatomy of a WPF-Enabled Application
Chapter 4: Building a Rich UI with Microsoft Expression Blend - Part I
Chapter 5: Building a Rich UI with Microsoft Expression Blend - Part II
Chapter 6: Special Effects
Chapter 7: Custom Controls
Chapter 8: Using WPF in the Enterprise
Chapter 9: Security
Chapter 10: WPF and Win32 Interop
Chapter 11: Advanced Development Concepts
Descarga:
Professional_WPF_Programming
Etiquetas:
.NET,
Advanced,
Chris Andrade,
Controls,
Custom,
Effects,
Expression Blend,
Interop,
Libros,
Mike Meyers,
Professional,
Scott Van Vliet,
Security,
Shawn Livermore,
Win32,
WPF,
Wrox
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 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>
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
Etiquetas:
C#,
Data Templates,
Demos,
Filas de Color,
Filtros en Cabecera,
FooterTemplate,
GridView,
HeaderRow,
HeaderTemplate,
ItemTemplate,
Javascript,
Lduenas,
ShowHeaderWhenEmpty,
StringBuilder,
Total en Pie,
WebForms
Suscribirse a:
Entradas (Atom)