MSDN - Manual de Windows Presentation Foundation Parte 1
Titulo: Manual de Windows Presentation Foundation Parte 1
Fuente Original: Microsoft Developer Network (MSDN)
Compilado Por: Luis Dueñas Huaroto (Lduenas)
Año de Compilación: 2008
Número de Páginas: 445
Indice del Manual de Windows Presentation Foundation (Parte 1)
1. Introducción a WPF
1.1. Introducción a Windows Presentation Foundation
1.2. Información General sobre Windows Presentation Foundation
1.3. Lo Nuevo en Windows Presentation Foundation Versión 3.5
2. Desarrollo de Aplicaciones
2.1. Información General sobre el Desarrollo de Aplicaciones
2.2. Administración de Aplicaciones
2.2.1. Información General sobre la Administración de Aplicaciones
2.2.2. Archivos c Windows Presentation Foundation
2.2.3. URIs de Paquete en Windows Presentation Foundation
2.2.4. Temas Cómo del Modelo de Aplicaciones
2.2.4.1. Cómo: Obtener y Establecer Propiedades en el Ambito de Aplicación
2.2.4.2. Cómo: Obtener y Establecer Recursos en el Ambito de Aplicación
2.2.4.3. Cómo: Obtener y Establecer el Código de Salida de Aplicaciones
2.2.4.4. Cómo: Obtener los Argumentos de Línea de Comandos
2.2.4.5. Cómo: Obtener el Objeto de Aplicación Actual
2.2.4.6. Cómo: Conservar y Restaurar Propiedades en el Ambito de Aplicación a través de Sesiones de Aplicación
2.2.4.7. Cómo: Cerrar una Aplicación
2.2.4.8. Cómo: Iniciar una Aplicación
2.2.4.9. Cómo: Usar un Diccionario de Recursos en el Ambito de Aplicación
2.3. Ventanas en Aplicaciones de Windows Presentation Foundation
2.3.1. Información General sobre Ventanas de WPF
2.3.2. Información General sobre Cuadros de Diálogo
2.3.3. Temas Cómo de la Administración de Ventanas
2.3.3.1. Cómo: Cambiar Automáticamente el Tamaño de una Ventana para que se Ajuste a su Contenido
2.3.3.2. Cómo: Obtener Todas las Ventanas de una Aplicación
2.3.3.3. Cómo: Obtener y Establecer la Ventana Principal de una Aplicación
2.3.3.4. Cómo: Abrir un Cuadro de Diálogo
2.3.3.5. Cómo: Abrir un Cuadro de Mensaje
2.3.3.6. Cómo: Abrir una Ventana
2.3.3.7. Cómo: Devolver el Resultado de un Cuadro de Diálogo
2.4. Navegación en Aplicaciones de Windows Presentation Foundation
2.4.1. Información General sobre Navegación
2.4.2. Información General sobre la Navegación Estructurada
2.4.3. Información General sobre Topologías de Navegación
2.4.4. Temas Cómo de Navegación
2.4.4.1. Cómo: Llamar a una Función de Página
2.4.4.2. Cómo: Determinar si una Página está Hospedada en un Explorador
2.4.4.3. Cómo: Obtener el Valor Devuelto por una Función de Página
2.4.4.4. Cómo: Navegar hacia Delante por el Historial de Navegación
2.4.4.5. Cómo: Navegar hacia Atrás por el Historial de Navegación
2.4.4.6. Cómo: Navegar hasta una Página
2.4.4.7. Cómo: Actualizar una Página
2.4.4.8. Cómo: Devolver Resultados de una Función de Página
2.4.4.9. Cómo: Establecer el Alto de una Ventana desde una Página
2.4.4.10. Cómo: Establecer el Ancho de una Ventana desde una Página
2.4.4.11. Cómo: Establecer el Título de una Ventana desde una Página
2.4.4.12. Cómo: Detener la Carga de una Página
2.4.4.13. Cómo: Usar Mailto: para Enviar Correo desde una Página
2.5. Extensibilidad de Aplicaciones
2.5.1. Información General sobre Complementos de WPF
2.5.2. Temas Cómo de Complementos de WPF
2.5.2.1. Cómo: Crear un Complemento que Devuelva una Interfaz de Usuario
2.5.2.2. Cómo: Crear un Complemento que sea una Interfaz de Usuario
2.6. Hospedar Aplicaciones de Windows Presentation Foundation
2.6.1. Información General sobre Aplicaciones de Explorador XAML de WPF
2.6.2. Información General sobre Aplicaciones Hospedadas en Windows Media Center para WPF
2.6.3. Host de Windows Presentation Foundation (PresentationHost.exe)
2.6.4. API No Administrada de WpfHostSupport
2.6.4.1. IEnumRAWINPUTDEVICE
2.6.4.2. IWpfHostSupport
2.7. Generar e Implementar Aplicaciones de WPF
2.7.1. Generar una Aplicación de WPF
2.7.2. Implementar una Aplicación de WPF
2.7.3. Temas Cómo de Generar e Implementar
2.7.3.1. Cómo: Crear un Archivo de Proyecto de Ejemplo para una Aplicación Independiente de WPF
2.7.3.2. Cómo: Crear un Archivo de Proyecto de Ejemplo para una Aplicación de Navegación Independiente de WPF
2.7.3.3. Cómo: Crear un Archivo de Proyecto de Ejemplo para una Aplicación de Explorador XAML de WPF
2.7.3.4. Cómo: Crear un Archivo de Proyecto de Ejemplo para una Biblioteca de Controles Personalizados de WPF
2.7.3.5. Cómo: Crear un Archivo de Proyecto de Ejemplo para una Aplicación Independiente de WPF que sólo contiene Código
2.7.3.6. Cómo: Configurar IIS 5.0 e IIS 6.0 para Implementar Aplicaciones de WPF
2.7.3.7. Configurar Visual Studio 2005 para Depurar una Aplicación de Explorador XAML
2.7.3.8. Configurar Visual Studio para Depurar una Aplicación de Explorador XAML y Llamar a un Servicio Web
2.7.3.9. Cómo: Determinar la Versión Instalada de Windows Presentation Foundation
2.7.3.10. Cómo: Detectar si .NET Framework 3.0 está Instalado
2.7.3.11. Cómo: Detectar si .NET Framework 3.5 está Instalado
2.7.3.12. Cómo: Detectar si está Instalado el Complemento XBAP para Firefox
2.8. Rendimiento
2.8.1. Niveles de Representación de Gráficos
2.8.2. Optimizar WPF: Rendimiento de Aplicaciones
2.8.2.1. Planear para Mejorar el Rendimiento de Aplicaciones
2.8.2.2. Aprovechar el Hardware
2.8.2.3. Presentación y Diseño
2.8.2.4. Imágenes y Gráficos 2D
2.8.2.5. Comportamiento de Objetos
2.8.2.6. Recursos de Aplicación
2.8.2.7. Texto
2.8.2.8. Enlace de Datos
2.8.2.9. Otras Recomendaciones
2.8.2.10. Herramientas y Recursos de Rendimiento de WPF
3. Elementos Fundamentales de WPF
3.1. Arquitectura de WPF
3.2. XAML
3.2.1. Información General sobre XAML
3.2.2. Terminología de la Sintaxis de XAML
3.2.3. Código Subyacente y XAML
3.2.4. XAML y Clases Personalizadas
3.2.5. Extensiones de Marcado y XAML
3.2.6. Espacios de Nombres y Asignación de Espacios de Nombres de XAML
3.2.7. Ambitos de Nombres de WPF
3.2.8. Estilos y Plantillas Insertados
3.2.9. Procesamiento de Espacios en Blanco en XAML
3.2.10. Clases TypeConverter y XAML
3.2.11. Entidades de Caracteres XML y XAML
3.2.12. Características de lenguaje (x:) de espacios de nombres XAML
3.2.12.1. Extensión de Marcado x:Array
3.2.12.2. Atributo x:Class
3.2.12.3. Atributo x:ClassModifier
3.2.12.4. Elemento de Directiva x:Code de XAML
3.2.12.5. Atributo x:FieldModifier
3.2.12.6. Atributo x:Key
3.2.12.7. Atributo x:Name
3.2.12.8. Extensión de Marcado x:Null
3.2.12.9. Atributo x:Shared
3.2.12.10. Extensiones de Marcado x:Static
3.2.12.11. Atributo x:Subclase
3.2.12.12. Extensión de Marcado x:Type
3.2.12.13. Atributo x:TypeArguments
3.2.12.14. Atributo x:Uid
3.2.12.15. Elemento de Directiva x:XData de XAML
3.2.12.16. Gramática de XamlName
3.2.12.17. Secuencia de Escape / Extensión de Marcado {}
3.2.12.18. Control de xml:lang en XAML
3.2.12.19. Control de xml:space en XAML
3.2.13. Extensiones de XAML de Espacio de Nombres de WPF
3.2.13.1. Enlazar Extensión de Marcado
3.2.13.2. Extensión de Marcado ColorConvertedBitmap
3.2.13.3. Extensión de Marcado ComponentResourceKey
3.2.13.4. Extensión de Marcado DynamicResource
3.2.13.5. Extensión de Marcado RelativeSource
3.2.13.6. Extensión de Marcado StaticResource
3.2.13.7. Extensión de Marcado TemplateBinding
3.2.13.8. Extensión de Marcado ThemeDictionary
3.2.13.9. Sintaxis de PropertyPath de XAML
3.2.13.10. Atributo PresentationOptions:Freeze
3.2.14. Características del Lenguaje de Compatibilidad de Marcado (mc:)
3.2.14.1. Atributo mc:Ignorable
3.2.14.2. Atributo mc:ProcessContent
3.3. Elementos Base
3.3.1. Información General sobre Elementos Base
3.3.2. Información General sobre Objetos Freezable
3.3.3. Información General sobre Alineación, Márgenes y Relleno
3.3.4. Temas Cómo sobre Elementos Base
3.3.4.1. Cómo: Hacer que un Elemento UIElement sea Transparente o Semitransparente
3.3.4.2. Cómo: Animar el Tamaño de un Elemento FrameworkElement
3.3.4.3. Cómo: Determinar si un Elemento Freezable está Inmovilizado
3.3.4.4. Cómo: Controlar un Evento Cargado
3.3.4.5. Cómo: Definir Márgenes de Elementos y Controles
3.3.4.6. Cómo: Hacer que un Elemento Freezable sea de Sólo Lectura
3.3.4.7. Cómo: Obtener una Copia Modificable de un Elemento Freezable de Sólo Lectura
3.3.4.8. Cómo: Voltear un Control UIElement Horizontal o Verticalmente
3.3.4.9. Cómo: Utilizar un Objeto ThicknessConverter
3.3.4.10. Cómo: Usar un Objeto LengthConverter
3.3.4.11. Cómo: Controlar el Evento ContextMenuOpening
3.4. Arbol de Elementos y Serialización
3.4.1. Arboles en WPF
3.4.2. Limitaciones en la Serialización de XamlWriter.Save
3.4.3. Inicialización de Elementos de Objeto No Incluidos en un Arbol de Elementos
3.4.4. Temas Cómo sobre el Arbol de Elementos y la Serialización
3.4.4.1. Cómo: Buscar un Elemento por su Nombre
3.4.4.2. Cómo: Invalidar el Arbol Lógico
3.5. Propiedades
3.5.1. Información General sobre las Propiedades de Dependencia
3.5.2. Información General sobre Propiedades Asociadas
3.5.3. Devoluciones de Llamada y Validación de las Propiedades de Dependencia
3.5.4. Propiedades de Dependencia Personalizadas
3.5.5. Metadatos de las Propiedades de Dependencia
3.5.6. Metadatos de las Propiedades de Marco de Trabajo
3.5.7. Prioridad de los Valores de Propiedades de Dependencia
3.5.8. Propiedades de Dependencia de Sólo Lectura
3.5.9. Herencia de Valores de Propiedad
3.5.10. Seguridad de las Propiedades de Dependencia
3.5.11. Modelos de Constructores Seguros para Objetos DependencyObject
3.5.12. Propiedades de Dependencia de Tipo de Colección
3.5.13. Carga de XAML y Propiedades de Dependencia
3.5.14. Temas Cómo sobre Propiedades
3.5.14.1. Cómo: Implementar una Propiedad de Dependencia
3.5.14.2. Cómo: Restaurar el Valor Predeterminado de una Propiedad de Dependencia
3.5.14.3. Cómo: Agregar un Tipo de Propietario para una Propiedad de Dependencia
3.5.14.4. Cómo: Registrar una Propiedad Asociada
3.5.14.5. Cómo: Invalidar Metadatos en una Propiedad de Dependencia
3.6. Eventos
3.6.1. Información General sobre Eventos Enrutados
3.6.2. Información General sobre Eventos Asociados
3.6.3. Eventos de Duración de Objetos
3.6.4. Marcar Eventos Enrutados como Controlados y Control de Clases
3.6.5. Eventos de Vista Previa
3.6.6. Eventos de Cambio de Propiedades
3.6.7. Control de Eventos en Visual Basic y WPF
3.6.8. Modelos WeakEvent
3.6.9. Temas Cómo sobre Eventos
3.6.9.1. Cómo: Agregar un Controlador de Eventos mediante Código
3.6.9.2. Cómo: Controlar un Evento Enrutado
3.6.9.3. Cómo: Crear un Evento Enrutado Personalizado
3.6.9.4. Cómo: Buscar el Elemento de Origen en un Controlador de Eventos
3.6.9.5. Cómo: Agregar Control de Clases a un Evento Enrutado
3.7. Acciones del Usuario y Comandos
3.7.1. Información General sobre Acciones del Usuario
3.7.2. Información General sobre Comandos
3.7.3. Información General sobre el Foco
3.7.4. Aplicar Estilo a los Controles al Recibir el Foco y FocusVisualStyle
3.7.5. Temas Cómo sobre Acciones del Usuario y Comandos
3.7.5.1. Cómo: Habilitar un Comando
3.7.5.2. Cómo: Cambiar el Tipo de Cursor
3.7.5.3. Cómo: Detectar el Estado de un Botón del Mouse
3.7.5.4. Cómo: Cambiar el Color de un Elemento mediante Eventos de Foco
3.7.5.5. Cómo: Aplicar FocusVisualStyle a un Control
3.7.5.6. Cómo: Detectar cuando se Presiona la Tecla Enter
3.7.5.7. Cómo: Crear un Efecto de Activación mediante Eventos
3.7.5.8. Cómo: Crear un Objeto que Siga el Puntero del Mouse
3.7.5.9. Cómo: Agregar un Comando a un Elemento de Menú
3.7.5.10. Cómo: Crear un Comando RoutedCommand
3.7.5.11. Cómo: Implementar ICommandSource
3.7.5.12. Cómo: Enlazar un Comando a un Control sin la Compatibilidad de Comandos
3.7.5.13. Cómo: Enlazar un Comando a un Control con la Compatibilidad de Comandos
3.8. Recursos WPF
3.8.1. Información General sobre Recursos
3.8.2. Recursos y Código
3.8.3. Diccionarios de Recursos Combinados
3.8.4. Temas Cómo de Recursos
3.8.4.1. Cómo: Definir y Hacer Referencia a un Recurso
3.8.4.2. Cómo: Usar Recursos de Aplicaciones
3.8.4.3. Cómo: Utilizar SystemFonts
3.8.4.4. Cómo: Usar Claves de Fuentes del Sistema
3.8.4.5. Cómo: Utilizar SystemParameters
3.8.4.6. Cómo: Utilizar Claves de Parámetros del Sistema
3.9. Estilos y Plantillas: Conceptual
3.9.1. Aplicar Estilos y Plantillas
3.9.2. Cómo: Buscar Elementos Generados por un Objeto ControlTemplate
3.10. Sistema de Diseño
3.11. Ajuste de Píxeles en Aplicaciones de WPF
3.12. Modelo de Subprocesos
Descarga
Manual_Windows_Presentation_Foundation_Parte1
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.
Mostrando las entradas con la etiqueta Estilos. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Estilos. Mostrar todas las entradas
miércoles, 29 de noviembre de 2017
El Manual del Día: Windows Presentation Foundation Parte 1
Etiquetas:
Acciones,
Arboles,
Comandos,
Diálogos,
Estilos,
Eventos,
Extensiones,
Gráficos,
Lduenas,
Manual,
MSDN,
Navegación,
Plantillas,
Propiedades,
Recursos,
Rendimiento,
Ventanas,
WPF,
XAML,
XBAP
viernes, 20 de febrero de 2015
El Demo del Día: Graficar Datos en el Cliente en ASP.NET MVC con JSON, Canvas y JavaScript
Graficar Datos en el Cliente en ASP.NET MVC con JSON, Canvas y JavaScript
Después de un par de semanas sin publicar un demo, les presento un post muy interesante de como trabajar en forma desconectada en el cliente para realizar consultas y gráficos de datos en ASP.NET MVC para lo cual usaremos jQuery, JSON, Canvas y JavaScript.
Requerimiento
Se desea crear una aplicación web que permita consultar los productos por categoría y mostrar los datos mas gráficos de diferentes tipos: Barras, Columnas, Lineas y Pie, pero el requisito es que sea desconectada tanto del Servidor de Datos como del Servidor Web, es decir, el filtro para la consulta y el gráfico se hará en el cliente.
Solución
- Crear una aplicación en ASP.NET MVC con un método de acción que se conecte a la BD una sola vez y devuelva un objeto con 2 listas: categorías y productos.
- Devolver una vista al cliente con la lista de categorías y la lista de tipos de gráficos.
- Ni bien carga la vista en el cliente hacer una llamada asíncrona usando $.ajax de jQuery para llamar a un método de acción que devuelva la lista de productos en formato JSON.
- Cuando el usuario seleccione una Categoría o seleccione un Tipo de Gráfico se llamará a una función JavaScript que filtrará los datos por la categoría seleccionada y los presentará en una tabla además lo dibujará en un Canvas.
Crear el Procedimiento Almacenado en la Base de Datos de SQL Server
Para el ejemplo usaremos la Base de Datos Northwind de SQL Server, en la cual crearemos el siguiente Procedimiento almacenado:
Create Procedure [dbo].[uspCategoriesProductsListar]
As
Select CategoryID,CategoryName From Categories
Select ProductID,ProductName,SupplierID,CategoryID,UnitPrice,UnitsInStock From Products
Crear la Librería de Clases Entidades del Negocio
Crear la librería de clases llamada: "Northwind.Librerias.EntidadesNegocio" y agregar la clase "beCategoria.cs":
namespace Northwind.Librerias.EntidadesNegocio
{
public class beCategoria
{
public int IdCategoria { get; set; }
public string Nombre { get; set; }
}
}
Agregar otra clase a la librería llamada "beProducto.cs":
namespace Northwind.Librerias.EntidadesNegocio
{
public class beProducto
{
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; }
}
}
Grabar y compilar la Librería de Entidades del Negocio.
Crear la Librería de Acceso a Datos
Crear la librería de clases llamada: "Northwind.Librerias.AccesoDatos", referenciar a la librería de clases de entidades creada anteriormente y agregar la clase "daCategoriaProducto.cs" y escribir el siguiente código:
using System;
using System.Collections.Generic; //List
using System.Data; //CommandType, CommandBehavior
using System.Data.SqlClient; //SqlConnection, SqlCommand, SqlDataReader
using Northwind.Librerias.EntidadesNegocio; //beCategoriaProducto, beCategoria, beProducto
namespace Northwind.Librerias.AccesoDatos
{
public class daCategoriaProducto
{
public beCategoriaProducto obtenerListas(SqlConnection con)
{
beCategoriaProducto obeCategoriaProducto = new beCategoriaProducto();
List<beCategoria> lbeCategoria = null;
List<beProducto> lbeProducto = null;
SqlCommand cmd = new SqlCommand("uspCategoriesProductsListar", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader drd = cmd.ExecuteReader();
if (drd != null)
{
lbeCategoria = new List<beCategoria>();
beCategoria obeCategoria;
int posIdCat = drd.GetOrdinal("CategoryID");
int posNomCat = drd.GetOrdinal("CategoryName");
while (drd.Read())
{
obeCategoria = new beCategoria();
obeCategoria.IdCategoria = drd.GetInt32(posIdCat);
obeCategoria.Nombre = drd.GetString(posNomCat);
lbeCategoria.Add(obeCategoria);
}
obeCategoriaProducto.ListaCategoria = lbeCategoria;
if (drd.NextResult())
{
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);
}
obeCategoriaProducto.ListaProducto = lbeProducto;
}
drd.Close();
}
return (obeCategoriaProducto);
}
}
}
Crear la Librería de Reglas del Negocio
Crear la librería de clases llamada: "Northwind.Librerias.ReglasNegocio", referenciar a la librería de clases de entidades y también a la de acceso a datos, luego agregar la clase "brCategoriaProducto.cs" y escribir el siguiente código:
using System;
using System.Configuration; //ConfigurationManager
using System.Data.SqlClient; //SqlConnection
using System.Collections.Generic; //List
using Northwind.Librerias.EntidadesNegocio; //beCategoriaProducto
using Northwind.Librerias.AccesoDatos; //daCategoriaProducto
namespace Northwind.Librerias.ReglasNegocio
{
public class brCategoriaProducto:brGeneral
{
public beCategoriaProducto obtenerListas()
{
beCategoriaProducto obeCategoriaProducto = null;
string CadenaConexion = ConfigurationManager.ConnectionStrings["conNW"]
.ConnectionString;
using (SqlConnection con = new SqlConnection(CadenaConexion))
{
try
{
con.Open();
daCategoriaProducto odaCategoriaProducto = new daCategoriaProducto();
obeCategoriaProducto = odaCategoriaProducto.obtenerListas(con);
}
catch (SqlException ex)
{
//grabarLog(ex);
}
catch (Exception ex)
{
//grabarLog(ex);
}
} //con.Close(); con.Dispose();
return (obeCategoriaProducto);
}
}
}
Nota: También es necesario hacer una referencia a la librería "System.Configuration" para leer la cadena de conexión definida en la aplicación.
Grabar la librería de reglas de negocio creada y compilarla.
Crear una Aplicación Web de ASP.NET MVC4 en C#
Seleccionar un nuevo proyecto de tipo: "Aplicación web de ASP.NET MVC4" y escribir como nombre "Canvas_GraficosDatos", luego seleccionar la opción "Vacio" y como motor de vista "Razor" y "Aceptar".
Crear un Controlador para el Producto
Clic derecho a la carpeta Controllers y seleccionar "Agregar" y luego "Controlador", llamarle al archivo "ProductoController.cs" y en opciones de plantillas dejarlo en plantilla vacía (Vaciar Controlador MVC). Luego escribir el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Northwind.LibBusEntities;
using Northwind.LibBusRules;
namespace HT03_Canvas_GraficosDatos.Controllers
{
public class ProductoController : Controller
{
public ActionResult Lista()
{
List<string> tipoGrafico = new List<string>();
tipoGrafico.Add("Barras");
tipoGrafico.Add("Columnas");
tipoGrafico.Add("Lineas");
tipoGrafico.Add("Pie");
ViewBag.Tipo = tipoGrafico;
brCategoriaProducto obrCategoriaProducto = new brCategoriaProducto();
beCategoriaProducto obeCategoriaProducto = obrCategoriaProducto.Listar();
Session["Productos"] = obeCategoriaProducto.ListaProducto;
return View(obeCategoriaProducto.ListaCategoria);
}
public JsonResult Filtro()
{
JsonResult rpta;
List<beProducto> lbeProducto = (List<beProducto>)Session["Productos"];
rpta = Json(lbeProducto, JsonRequestBehavior.AllowGet);
return (rpta);
}
}
}
Crear una Hoja de Estilos para la Vista
Primero crear una carpeta llamada "Content", luego clic derecho "Agregar" y luego "Hoja de estilos" y como nombre llamarle "ACME.css" y escribir el siguiente código:
body {
background-color:lightgray;
}
.Titulo {
background-color:black;
color:white;
font-size:x-large;
text-transform:uppercase;
}
.Subtitulo {
background-color:white;
color:black;
font-size:large;
text-transform:capitalize;
font-weight:bold;
}
.AnchoTotal {
width:100%;
}
.FilaCabecera {
background-color:gray;
color:white;
}
.FilaDatos {
background-color:white;
color:black;
}
.Cuadro {
background-color:white;
border-style:double;
}
Crear la Vista Productos para mostrar los datos
Ir al controlador y ubicarse sobre el método "Lista" (acción), clic derecho y seleccionar "Agregar vista", seleccionar el check "Crear una vista fuertemente tipada" y escribir el siguiente código:
@using Northwind.LibBusEntities
@model List<beCategoria>
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Lista</title>
<link href="~/Content/Styles/ACME.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script src="~/Scripts/Rutinas.js"></script>
</head>
<body>
<div>
<table class="AnchoTotal">
<tr class="Titulo">
<td colspan="2">
Graficar Datos en el Cliente en ASP.NET MVC con JSON, Canvas y JavaScript
</td>
</tr>
<tr class="Subtitulo">
<td colspan="2">Gráfico de Precios de Productos x Categoria</td>
</tr>
<tr>
<td style="width:40%">
Selecciona una Categoria: @Html.DropDownList("idCategoria",
new SelectList(Model,"Codigo","Nombre"))
</td>
<td style="width:60%">
Selecciona el Tipo de Grafico: @Html.DropDownList("tipo",
new SelectList(ViewBag.Tipo))
</td>
</tr>
<tr>
<td style="vertical-align:top">
<table class="AnchoTotal">
<thead>
<tr class="FilaCabecera">
<td style="width:80%">Nombre del Producto</td>
<td style="width:20%">Stock</td>
</tr>
</thead>
<tbody id="tbProducto">
</tbody>
</table>
</td>
<td>
<canvas id="canvas" width="600" height="400" class="Cuadro"/>
</td>
</tr>
</table>
</div>
</body>
</html>
Nota: La función asociada al $(document).ready se ejecuta ni bien carga la pagina y se llama en forma asíncrona al método de acción "Filtro" que devuelve un JSON con la lista de productos y por JavaScript se crea el filtro, se muestra la tabla y el gráfico de acuerdo a la categoría seleccionada y al tipo de gráfico.
Modificar el archivo web.config para incluir la cadena de conexión
<configuration>
<connectionStrings>
<add name="conNW" providerName="SQLServer"
connectionString="uid=UsuarioNW;pwd=123456;
data source=DSOFT\Sqlexpress;database=Northwind"/>
</connectionStrings>
.....
</configuration>
Configurar el inicio y ejecutar la aplicación web
Para probar la aplicación web debemos configurar el inicio para lo cual nos vamos a la carpeta "App_Start" y abrimos el archivo "RouteConfig.cs" cambiando el nombre del controlador y la acción tal como sigue: controller = "Producto", action = "Lista".
Ejecución y Pruebas de la Aplicación Web ASP.NET MVC
Finalmente, grabar y pulsar F5 para ejecutar la aplicación, mostrándose el resultado similar a la siguiente figura:
Por defecto se muestra la categoría "Bebidas" y en el tipo de gráfico "Barras", cambiar el tipo de gráfico a "Columnas" y se verá la siguiente figura:
Probar ahora con el gráfico de "Lineas" y se mostrará algo similar a la siguiente figura:
Finalmente, cambiar el tipo de gráfico a "Pie" y se verá lo siguiente:
Comentario Final
En este post hemos visto como trabajar en forma desconectada, y también hemos aprendido a crear grillas (tablas) y gráficos (canvas) sin usar controles, sino mediante código JavaScript.
Además hemos hecho llamada asíncrona mediante Ajax de jQuery y retornado los datos como un arreglo en notación JavaScript (JSON).
Esta forma de trabajo (desconectada) es muy útil en aplicaciones móviles donde la conexión al servidor web es limitada, por lo cual una sola vez se trae los datos y todo se maneja en el cliente (Browser).
Este demo es uno de los tantos que se realiza en el programa Web Developer. Espero les sirva.
Descarga
DemoDia_GraficoDatosCliente
Después de un par de semanas sin publicar un demo, les presento un post muy interesante de como trabajar en forma desconectada en el cliente para realizar consultas y gráficos de datos en ASP.NET MVC para lo cual usaremos jQuery, JSON, Canvas y JavaScript.
Requerimiento
Se desea crear una aplicación web que permita consultar los productos por categoría y mostrar los datos mas gráficos de diferentes tipos: Barras, Columnas, Lineas y Pie, pero el requisito es que sea desconectada tanto del Servidor de Datos como del Servidor Web, es decir, el filtro para la consulta y el gráfico se hará en el cliente.
Solución
- Crear una aplicación en ASP.NET MVC con un método de acción que se conecte a la BD una sola vez y devuelva un objeto con 2 listas: categorías y productos.
- Devolver una vista al cliente con la lista de categorías y la lista de tipos de gráficos.
- Ni bien carga la vista en el cliente hacer una llamada asíncrona usando $.ajax de jQuery para llamar a un método de acción que devuelva la lista de productos en formato JSON.
- Cuando el usuario seleccione una Categoría o seleccione un Tipo de Gráfico se llamará a una función JavaScript que filtrará los datos por la categoría seleccionada y los presentará en una tabla además lo dibujará en un Canvas.
Crear el Procedimiento Almacenado en la Base de Datos de SQL Server
Para el ejemplo usaremos la Base de Datos Northwind de SQL Server, en la cual crearemos el siguiente Procedimiento almacenado:
Create Procedure [dbo].[uspCategoriesProductsListar]
As
Select CategoryID,CategoryName From Categories
Select ProductID,ProductName,SupplierID,CategoryID,UnitPrice,UnitsInStock From Products
Crear la Librería de Clases Entidades del Negocio
Crear la librería de clases llamada: "Northwind.Librerias.EntidadesNegocio" y agregar la clase "beCategoria.cs":
namespace Northwind.Librerias.EntidadesNegocio
{
public class beCategoria
{
public int IdCategoria { get; set; }
public string Nombre { get; set; }
}
}
Agregar otra clase a la librería llamada "beProducto.cs":
namespace Northwind.Librerias.EntidadesNegocio
{
public class beProducto
{
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; }
}
}
Finalmente, agregar una clase llamada "beCategoriaProducto.cs" que agrupe las 2 listas:
using System;
using System.Collections.Generic;
namespace Northwind.Librerias.EntidadesNegocio
{
public class beCategoriaProducto
{
public List<beCategoria> ListaCategoria { get; set; }
public List<beProducto> ListaProducto { get; set; }
}
}
Crear la Librería de Acceso a Datos
Crear la librería de clases llamada: "Northwind.Librerias.AccesoDatos", referenciar a la librería de clases de entidades creada anteriormente y agregar la clase "daCategoriaProducto.cs" y escribir el siguiente código:
using System;
using System.Collections.Generic; //List
using System.Data; //CommandType, CommandBehavior
using System.Data.SqlClient; //SqlConnection, SqlCommand, SqlDataReader
using Northwind.Librerias.EntidadesNegocio; //beCategoriaProducto, beCategoria, beProducto
namespace Northwind.Librerias.AccesoDatos
{
public class daCategoriaProducto
{
public beCategoriaProducto obtenerListas(SqlConnection con)
{
beCategoriaProducto obeCategoriaProducto = new beCategoriaProducto();
List<beCategoria> lbeCategoria = null;
List<beProducto> lbeProducto = null;
SqlCommand cmd = new SqlCommand("uspCategoriesProductsListar", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader drd = cmd.ExecuteReader();
if (drd != null)
{
lbeCategoria = new List<beCategoria>();
beCategoria obeCategoria;
int posIdCat = drd.GetOrdinal("CategoryID");
int posNomCat = drd.GetOrdinal("CategoryName");
while (drd.Read())
{
obeCategoria = new beCategoria();
obeCategoria.IdCategoria = drd.GetInt32(posIdCat);
obeCategoria.Nombre = drd.GetString(posNomCat);
lbeCategoria.Add(obeCategoria);
}
obeCategoriaProducto.ListaCategoria = lbeCategoria;
if (drd.NextResult())
{
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);
}
obeCategoriaProducto.ListaProducto = lbeProducto;
}
drd.Close();
}
return (obeCategoriaProducto);
}
}
}
Grabar y compilar la librería de acceso a datos creada.
Crear la Librería de Reglas del Negocio
Crear la librería de clases llamada: "Northwind.Librerias.ReglasNegocio", referenciar a la librería de clases de entidades y también a la de acceso a datos, luego agregar la clase "brCategoriaProducto.cs" y escribir el siguiente código:
using System;
using System.Configuration; //ConfigurationManager
using System.Data.SqlClient; //SqlConnection
using System.Collections.Generic; //List
using Northwind.Librerias.EntidadesNegocio; //beCategoriaProducto
using Northwind.Librerias.AccesoDatos; //daCategoriaProducto
namespace Northwind.Librerias.ReglasNegocio
{
public class brCategoriaProducto:brGeneral
{
public beCategoriaProducto obtenerListas()
{
beCategoriaProducto obeCategoriaProducto = null;
string CadenaConexion = ConfigurationManager.ConnectionStrings["conNW"]
.ConnectionString;
using (SqlConnection con = new SqlConnection(CadenaConexion))
{
try
{
con.Open();
daCategoriaProducto odaCategoriaProducto = new daCategoriaProducto();
obeCategoriaProducto = odaCategoriaProducto.obtenerListas(con);
}
catch (SqlException ex)
{
//grabarLog(ex);
}
catch (Exception ex)
{
//grabarLog(ex);
}
} //con.Close(); con.Dispose();
return (obeCategoriaProducto);
}
}
}
Nota: También es necesario hacer una referencia a la librería "System.Configuration" para leer la cadena de conexión definida en la aplicación.
Grabar la librería de reglas de negocio creada y compilarla.
Crear una Aplicación Web de ASP.NET MVC4 en C#
Seleccionar un nuevo proyecto de tipo: "Aplicación web de ASP.NET MVC4" y escribir como nombre "Canvas_GraficosDatos", luego seleccionar la opción "Vacio" y como motor de vista "Razor" y "Aceptar".
Crear un Controlador para el Producto
Clic derecho a la carpeta Controllers y seleccionar "Agregar" y luego "Controlador", llamarle al archivo "ProductoController.cs" y en opciones de plantillas dejarlo en plantilla vacía (Vaciar Controlador MVC). Luego escribir el siguiente código:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Northwind.LibBusEntities;
using Northwind.LibBusRules;
namespace HT03_Canvas_GraficosDatos.Controllers
{
public class ProductoController : Controller
{
public ActionResult Lista()
{
List<string> tipoGrafico = new List<string>();
tipoGrafico.Add("Barras");
tipoGrafico.Add("Columnas");
tipoGrafico.Add("Lineas");
tipoGrafico.Add("Pie");
ViewBag.Tipo = tipoGrafico;
brCategoriaProducto obrCategoriaProducto = new brCategoriaProducto();
beCategoriaProducto obeCategoriaProducto = obrCategoriaProducto.Listar();
Session["Productos"] = obeCategoriaProducto.ListaProducto;
return View(obeCategoriaProducto.ListaCategoria);
}
public JsonResult Filtro()
{
JsonResult rpta;
List<beProducto> lbeProducto = (List<beProducto>)Session["Productos"];
rpta = Json(lbeProducto, JsonRequestBehavior.AllowGet);
return (rpta);
}
}
}
Primero crear una carpeta llamada "Content", luego clic derecho "Agregar" y luego "Hoja de estilos" y como nombre llamarle "ACME.css" y escribir el siguiente código:
body {
background-color:lightgray;
}
.Titulo {
background-color:black;
color:white;
font-size:x-large;
text-transform:uppercase;
}
.Subtitulo {
background-color:white;
color:black;
font-size:large;
text-transform:capitalize;
font-weight:bold;
}
.AnchoTotal {
width:100%;
}
.FilaCabecera {
background-color:gray;
color:white;
}
.FilaDatos {
background-color:white;
color:black;
}
.Cuadro {
background-color:white;
border-style:double;
}
Crear la Vista Productos para mostrar los datos
Ir al controlador y ubicarse sobre el método "Lista" (acción), clic derecho y seleccionar "Agregar vista", seleccionar el check "Crear una vista fuertemente tipada" y escribir el siguiente código:
@using Northwind.LibBusEntities
@model List<beCategoria>
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Lista</title>
<link href="~/Content/Styles/ACME.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script src="~/Scripts/Rutinas.js"></script>
</head>
<body>
<div>
<table class="AnchoTotal">
<tr class="Titulo">
<td colspan="2">
Graficar Datos en el Cliente en ASP.NET MVC con JSON, Canvas y JavaScript
</td>
</tr>
<tr class="Subtitulo">
<td colspan="2">Gráfico de Precios de Productos x Categoria</td>
</tr>
<tr>
<td style="width:40%">
Selecciona una Categoria: @Html.DropDownList("idCategoria",
new SelectList(Model,"Codigo","Nombre"))
</td>
<td style="width:60%">
Selecciona el Tipo de Grafico: @Html.DropDownList("tipo",
new SelectList(ViewBag.Tipo))
</td>
</tr>
<tr>
<td style="vertical-align:top">
<table class="AnchoTotal">
<thead>
<tr class="FilaCabecera">
<td style="width:80%">Nombre del Producto</td>
<td style="width:20%">Stock</td>
</tr>
</thead>
<tbody id="tbProducto">
</tbody>
</table>
</td>
<td>
<canvas id="canvas" width="600" height="400" class="Cuadro"/>
</td>
</tr>
</table>
</div>
</body>
</html>
Crear el archivo JavaScript con el código cliente
Antes que nada crear una carpeta llamada "Scripts" y arrastrar del explorador de Windows el archivo de jQuery: "jquery-1.7.1.min.js", luego agregar un archivo de JavaScript llamado "Rutinas.js" y escribir el siguiente código:
$(document).ready(function () {
var rpta;
var cboCategoria = document.getElementById("idCategoria");
cboCategoria.onchange = function () { crearTablaGrafico(); }
var cboTipo = document.getElementById("tipo");
cboTipo.onchange = function () { crearTablaGrafico(); }
$.ajax({
type: "post",
url: "/Producto/Filtro",
contentType: "application/json;charset=utf-8",
dataType: "json",
success: exito,
error: error
});
function crearTablaGrafico() {
var idCategoria = cboCategoria.value * 1;
var tbProducto = document.getElementById("tbProducto");
var tipo = cboTipo.value;
var contenido = "";
var canvas = document.getElementById("canvas");
var contexto = canvas.getContext("2d");
if (contexto != null) graficar(rpta);
function graficar(rpta) {
//Crear Degradado
var deg = contexto.createLinearGradient(0, 0, canvas.width, canvas.height);
deg.addColorStop(1, "aqua");
deg.addColorStop(0.1, "blue");
//Dibujar Rectangulo Degradado
contexto.fillStyle = deg;
contexto.fillRect(0, 0, canvas.width, canvas.height);
//Variables para los calculos
var x = 10;
var y = 20;
var valor = 0;
var escala = 0;
var maximo = 0;
var total = 0;
if (tipo != "Pie") {
maximo = calcularMaximo(idCategoria);
if (tipo == "Barras") escala = Math.abs((canvas.width - 180) / maximo);
else {
escala = Math.abs((canvas.height - 120) / maximo);
x = 50;
}
}
else total = calcularTotal(idCategoria);
var centroX = Math.floor(canvas.width / 2);
var centroY = Math.floor(canvas.height / 2);
var radio = Math.floor(canvas.width / 4);
var anguloInicio = 0;
var arco = 0;
var anguloFin = 0;
//Dibujar el grafico de acuerdo al tipo
for (i = 0; i < rpta.length; i++) {
if (rpta[i].IdCategoria == idCategoria) {
contenido += "<tr class='FilaDatos'><td>" + rpta[i].Nombre + "</td>" +
"<td class='Derecha'>" + rpta[i].PrecioUnitario + "</td></tr>";
switch(tipo)
{
case "Barras":
x = 10;
contexto.fillStyle = "white";
contexto.font = "10px arial";
contexto.fillText(rpta[i].Nombre, x, y);
x = 150;
valor = rpta[i].PrecioUnitario * escala;
contexto.fillStyle = "yellow";
contexto.fillRect(x, y - 10, valor, 10);
contexto.fillStyle = "white";
contexto.fillText(rpta[i].PrecioUnitario, x + valor + 5, y);
y = y + 20;
break;
case "Columnas":
contexto.save();
contexto.translate(x, canvas.height - 10);
contexto.rotate(-(Math.PI / 3));
contexto.fillStyle = "white";
contexto.fillText(rpta[i].Nombre, 0, 0);
contexto.restore();
contexto.fillStyle = "yellow";
valor = (canvas.height - 100 - (rpta[i].PrecioUnitario*escala));
contexto.fillRect(x, valor, 10, rpta[i].PrecioUnitario * escala);
contexto.fillStyle = "white";
contexto.fillText(rpta[i].PrecioUnitario, x, valor - 10);
x += 40;
break;
case "Lineas":
contexto.save();
contexto.translate(x, canvas.height - 10);
contexto.rotate(-(Math.PI / 3));
contexto.fillStyle = "white";
contexto.fillText(rpta[i].Nombre, 0, 0);
contexto.restore();
contexto.strokeStyle = "yellow";
contexto.lineWidth = 3;
if (x== 50) {
contexto.beginPath();
valor = Math.floor(canvas.height - 100 - (rpta[i].PrecioUnitario) * escala);
contexto.moveTo(x, valor);
}
valor = Math.floor(canvas.height - 100 - (rpta[i].PrecioUnitario * escala));
contexto.lineTo(x, valor);
contexto.stroke();
contexto.fillStyle = "white";
contexto.fillText(rpta[i].PrecioUnitario, x, valor - 10);
x += 40;
break;
case "Pie":
arco=(rpta[i].PrecioUnitario * 2 * Math.PI) / total;
anguloFin = anguloInicio + arco;
contexto.save();
contexto.beginPath();
contexto.moveTo(centroX, centroY);
contexto.arc(centroX, centroY, radio, anguloInicio, anguloFin, false);
contexto.fillStyle = '#' + Math.floor(Math.random() * 16777215).toString(16);
contexto.fill();
contexto.closePath();
contexto.restore();
contexto.save();
contexto.translate(centroX, centroY);
contexto.rotate(anguloInicio);
x = Math.floor(canvas.width * 0.15) - 10;
y = Math.floor(canvas.height * 0.05);
contexto.fillStyle = "white";
contexto.fillText(rpta[i].PrecioUnitario, x, y);
contexto.restore();
anguloInicio = anguloFin;
break;
}
}
tbProducto.innerHTML = contenido;
}
}
}
function calcularTotal(idCategoria) {
var total = 0;
for (i = 0; i < rpta.length; i++) {
if (rpta[i].IdCategoria == idCategoria) {
total += rpta[i].PrecioUnitario;
}
}
return total;
}
function calcularMaximo(idCategoria) {
var max = 0;
for (i = 0; i < rpta.length; i++) {
if (rpta[i].IdCategoria == idCategoria) {
if (rpta[i].PrecioUnitario>max) max = rpta[i].PrecioUnitario;
}
}
return max;
}
function exito(data) {
rpta = data;
crearTablaGrafico();
}
function error(data) {
alert(data.status + " - " + data.statusText);
}
});
Nota: La función asociada al $(document).ready se ejecuta ni bien carga la pagina y se llama en forma asíncrona al método de acción "Filtro" que devuelve un JSON con la lista de productos y por JavaScript se crea el filtro, se muestra la tabla y el gráfico de acuerdo a la categoría seleccionada y al tipo de gráfico.
Modificar el archivo web.config para incluir la cadena de conexión
<configuration>
<connectionStrings>
<add name="conNW" providerName="SQLServer"
connectionString="uid=UsuarioNW;pwd=123456;
data source=DSOFT\Sqlexpress;database=Northwind"/>
</connectionStrings>
.....
</configuration>
Configurar el inicio y ejecutar la aplicación web
Para probar la aplicación web debemos configurar el inicio para lo cual nos vamos a la carpeta "App_Start" y abrimos el archivo "RouteConfig.cs" cambiando el nombre del controlador y la acción tal como sigue: controller = "Producto", action = "Lista".
Ejecución y Pruebas de la Aplicación Web ASP.NET MVC
Finalmente, grabar y pulsar F5 para ejecutar la aplicación, mostrándose el resultado similar a la siguiente figura:
Por defecto se muestra la categoría "Bebidas" y en el tipo de gráfico "Barras", cambiar el tipo de gráfico a "Columnas" y se verá la siguiente figura:
Probar ahora con el gráfico de "Lineas" y se mostrará algo similar a la siguiente figura:
Finalmente, cambiar el tipo de gráfico a "Pie" y se verá lo siguiente:
Comentario Final
En este post hemos visto como trabajar en forma desconectada, y también hemos aprendido a crear grillas (tablas) y gráficos (canvas) sin usar controles, sino mediante código JavaScript.
Además hemos hecho llamada asíncrona mediante Ajax de jQuery y retornado los datos como un arreglo en notación JavaScript (JSON).
Esta forma de trabajo (desconectada) es muy útil en aplicaciones móviles donde la conexión al servidor web es limitada, por lo cual una sola vez se trae los datos y todo se maneja en el cliente (Browser).
Este demo es uno de los tantos que se realiza en el programa Web Developer. Espero les sirva.
Descarga
DemoDia_GraficoDatosCliente
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
Suscribirse a:
Entradas (Atom)









