Para casi todas las aplicaciones web de presentación de datos, uno de los objetivos principales es organizar la forma en que se muestran los datos y evitar sentimientos confusos para los usuarios. Mostrar 20 registros por página es ciertamente aceptable, pero mostrar 10.000 registros por página puede causar inconvenientes a los usuarios. Dividir los datos en varias páginas para su visualización, es decir, paginar los datos, es la forma más común de resolver este tipo de problemas.
1. Descripción general
ASP.NET solo proporciona un control que admite la paginación de datos, a saber, el control de paginación DataGrid. Sin embargo, es más adecuado para su uso en entornos de Intranet, las funciones proporcionadas por el control de paginación DataGrid no parecen funcionar. ser suficiente para construir una aplicación web flexible. Una de las razones es que el control DataGrid impone restricciones sobre dónde los diseñadores web pueden colocar controles de paginación y sobre la apariencia de los controles de paginación. Por ejemplo, el control DataGrid no permite la ubicación vertical de controles de paginación. Otro control que puede aprovechar la tecnología de paginación es el Repetidor. Los desarrolladores web pueden usar el control Repetidor para configurar rápidamente el método de visualización de datos, pero la función de paginación requiere que los desarrolladores la implementen ellos mismos. Las fuentes de datos cambian constantemente y los métodos de presentación de datos varían ampliamente. Obviamente, sería una pérdida de tiempo personalizar los controles de paginación para estas condiciones cambiantes. Construir un control de paginación universal que no se limite a controles de presentación específicos ayudará enormemente a ahorrar tiempo.
Un excelente control de datos universal no sólo proporciona funciones de localización regulares, sino que también puede:
⑴ Proporcione los botones de navegación de paginación "Página de inicio", "Página anterior", "Página siguiente" y "Última página".
⑵ Ajuste su estado de acuerdo con la situación de visualización de datos, es decir, tiene sensibilidad de datos. Si el control de paginación está configurado para mostrar 10 registros por página, pero en realidad solo hay 9 registros, entonces el control de paginación no debe mostrarse cuando los datos se dividen en varias páginas para su visualización, el "Inicio" y el "Top" de; la primera página No se debe mostrar el botón "Página", ni los botones "Página siguiente" y "Última página" de la última página.
⑶ No se puede confiar en controles de visualización de datos específicos.
⑷ Capacidad para adaptarse a diversas fuentes de datos existentes y futuras.
⑸ El modo de visualización debe configurarse fácilmente e integrarse fácilmente en varias aplicaciones.
⑹ Cuando la localización esté lista, recuerde otros controles.
⑺ Incluso los diseñadores web sin experiencia deberían poder utilizarlo sin dificultad.
⑻ Proporcione datos de atributos sobre la información de paginación.
Actualmente existen algunos controles comerciales en el mercado que brindan las funciones anteriores, pero todos son costosos. Para muchos desarrolladores, construir usted mismo un control de paginación universal es la opción ideal.
La Figura 1 muestra la interfaz en ejecución del control de paginación universal en este artículo, en el que el control utilizado para la visualización es un control Repetidor. El control de paginación consta de dos tipos de componentes: cuatro botones de navegación y un conjunto de enlaces de números de página.
Los usuarios pueden cambiar fácilmente los controles de visualización y cambiar la apariencia del propio control de paginación. Por ejemplo, el control de visualización que coopera con el control de paginación se reemplaza por un control DataGrid, y el enlace del número de página y cuatro botones de navegación se muestran en dos filas.
ASP.NET admite tres formas de crear controles web personalizados: controles de usuario, controles compuestos y controles personalizados. El nombre del tercer tipo de control, el control personalizado, es fácilmente engañoso. De hecho, los tres controles deberían considerarse controles personalizados. La diferencia entre los controles compuestos y los llamados controles personalizados de Microsoft es que los primeros requieren el método CreateChildControls(). El método CreateChildControls() permite que el control se vuelva a dibujar en función de ciertos eventos. Para el buscapersonas universal de este artículo, usaremos un control compuesto.
El siguiente diagrama de secuencia UML describe el mecanismo general del control de paginación universal.
Aunque nuestro objetivo es hacer que el control de paginación universal sea independiente del control que representa los datos, es obvio que debe haber alguna forma para que el control de paginación acceda a los datos. Cada control que hereda de la clase Control proporciona un evento DataBinding. Registramos el buscapersonas como escucha del evento DataBinding, para que el buscapersonas pueda conocer los datos y modificarlos. Dado que todos los controles que heredan de la clase Control tienen este evento DataBinding, el control de buscapersonas logra el objetivo de no depender de un control de presentación de datos específico; en otras palabras, el control de buscapersonas se puede vincular a todos los controles que se derivan de la clase Control. Es decir, se puede vincular a casi todos los controles web.
2. Funciones principales
Cuando el control de presentación activa el evento DataBinding, el control de paginación puede obtener la propiedad DataSource. Desafortunadamente, Microsoft no proporciona interfaces que implementen todas las clases de enlace de datos, como IdataSourceProvider, y no todos los controles que heredan de la clase Control o WebControl tienen una propiedad DataSource, por lo que no tiene sentido actualizar a la clase Control, la única factible. camino El método consiste en operar directamente la propiedad DataSoruce a través de la API Reflection. Antes de analizar los métodos del controlador de eventos, cabe señalar que para registrar un controlador de eventos, primero debe obtener una referencia al control de presentación. El control de paginación expone una propiedad de cadena simple BindToControl:
cadena pública BindToControl
{
conseguir
{
si (_bindcontrol == nulo)
throw new NullReferenceException ("Antes de usar el control de paginación, vincúlese a un control configurando la propiedad BindToControl.");
devolver _bindcontrol;}
establecer{_bindcontrol=valor;}
}
Este método es muy importante, por lo que es mejor enviar un mensaje más claro en lugar de lanzar la excepción NullReferenceException estándar. En el método OnInit del control de paginación resolvemos la referencia al control de presentación. Este ejemplo debe utilizar el controlador de eventos OnInit (en lugar del constructor) para garantizar que la página aspx compilada JIT tenga configurado BindToControl.
anulación protegida anulación OnInit (EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += nuevo EventHandler(BoundControl_DataBound);
base.OnInit(e);
...
}
La operación de búsqueda del control de presentación se completa buscando el control principal del control de paginación. Aquí, el principal es la página misma. Es peligroso utilizar Parent de esta manera. Por ejemplo, si el control de paginación está incrustado en otro control, como un control Table, la referencia Parent en realidad será una referencia al control Table. Dado que el método FindControl solo busca en la colección de controles actual, es imposible buscar a menos que el control de presentación esté en la colección. Un enfoque más seguro es buscar recursivamente en la colección de controles hasta encontrar el control de destino.
Después de encontrar BoundControl, registramos el control de paginación como escucha del evento DataBinding. Dado que el control de paginación opera en una fuente de datos, es importante que este controlador de eventos sea el último en la cadena de llamadas. Sin embargo, siempre que el control de presentación registre el controlador de eventos DataBinding en el controlador de eventos OnInit (el comportamiento predeterminado), no habrá ningún problema cuando el control de paginación opere la fuente de datos.
El controlador de eventos DataBound es responsable de obtener la propiedad DataSource del control de presentación.
vacío privado BoundControl_DataBound (remitente del objeto, System.EventArgs e)
{
si (HasParentControlCalledDataBinding) regresa;
Tipo tipo = remitente.GetType();
_datasource = type.GetProperty("Fuente de datos");
si (_datasource == nulo)
throw new NotSupportedException("El control de paginación requiere que el control de presentación contenga un DataSource.");
datos del objeto = _datasource.GetGetMethod().Invoke(remitente,null);
_builder = Adaptadores[data.GetType()];
si (_builder == nulo)
throw new NullReferenceException("El adaptador apropiado no está instalado para manejar el siguiente tipo de fuente de datos: "+data.GetType());
_builder.Source = datos;
ApplyDataSensitivityRules();
VincularParent();
RaiseEvent(Actualización de datos,esto);
}
En DataBound, intentamos obtener la propiedad DataSource a través de la API de Reflection y luego devolvemos una referencia a la fuente de datos real. Ahora que se conoce la fuente de datos, el control de paginación también debe saber cómo operar en la fuente de datos. Para hacer que el control de paginación no dependa de un control de presentación específico, el problema es mucho más complicado. Sin embargo, hacer que el control de paginación dependa de una fuente de datos específica frustra el objetivo de diseñar un control de paginación flexible. Necesitamos utilizar una arquitectura de complemento para garantizar que el control de paginación pueda manejar varias fuentes de datos, ya sea la fuente de datos proporcionada por .NET o una fuente de datos personalizada.
Para proporcionar una arquitectura conectable, escalable y robusta, construiremos una solución utilizando el patrón Builder [GoF].
Figura 4
La interfaz IDataSourceAdapter define los elementos más básicos necesarios para que el control de paginación opere los datos, lo que equivale a un "enchufe".
interfaz pública IDataSourceAdapter
{
int TotalCount{get;}
objeto GetPaggedData(int inicio,int final);
}
La propiedad TotalCount devuelve el número total de elementos contenidos en la fuente de datos antes de procesar los datos, mientras que el método GetPaggedData devuelve un subconjunto de los datos originales. Por ejemplo: suponiendo que la fuente de datos es una matriz que contiene 20 elementos, se muestra el control de paginación. los datos como 10 elementos por página, entonces el subconjunto de elementos en la primera página son los elementos de la matriz 0-9, y el subconjunto de elementos en la segunda página son los elementos de la matriz 10-19. DataViewAdapter proporciona un complemento de tipo DataView:
clase interna DataViewAdapter:IDataSourceAdapter
{
DataView privado _view;
DataViewAdapter interno (vista DataView)
{
_vista = ver;
}
público int TotalCount
{
obtener {return (_view == null) 0: _view.Table.Rows.Count;}
}
objeto público GetPaggedData (int inicio, int fin)
{
Tabla de datos = _view.Table.Clone();
para (int i = inicio;i<=fin && i<= TotalCount;i++)
{
tabla.ImportRow(_view[i-1].Row);
}
tabla de retorno;
}
}
DataViewAdapter implementa el método GetPaggedData de IDataSourceAdapter, que clona el DataTable original e importa los datos del DataTable original al nuevo DataTable. La visibilidad de esta clase se establece intencionalmente en interna para ocultar los detalles de implementación a los desarrolladores web y proporcionar una interfaz más simple a través de la clase Builder.
clase abstracta pública AdapterBuilder
{
objeto privado _source;
vacío privado CheckForNull();
{
if (_source == null) throw new NullReferenceException ("Se debe proporcionar una fuente de datos legal");
}
objeto virtual público Fuente
{
conseguir
{
CheckForNull();
devolver _fuente;}
colocar
{
_fuente = valor;
CheckForNull();
}
}
Adaptador IDataSourceAdapter abstracto público{get;}
}
La clase abstracta AdapterBuilder proporciona una interfaz más manejable para el tipo IdataSourceAdapter. Debido al mayor nivel de abstracción, ya no tenemos que usar IdataSourceAdapter directamente. Al mismo tiempo, AdapterBuilder también proporciona instrucciones para realizar el preprocesamiento antes de paginar los datos. Además, este generador también hace que la clase de implementación real, como DataViewAdapter, sea transparente para los usuarios del control de paginación:
clase pública DataTableAdapterBuilder:AdapterBuilder
{
Adaptador de vista de datos privado _adapter
Adaptador de vista de datos privado
;
{
conseguir
{
si (_adapter == nulo)
{
Tabla de datos = (Tabla de datos) Fuente;
_adapter = nuevo DataViewAdapter(table.DefaultView);
}
devolver _adaptador;
}
}
anulación pública del adaptador IDataSourceAdapter
{
conseguir
{
devolver ViewAdapter;
}
}
}
clase pública DataViewAdapterBuilder:AdapterBuilder
{
Adaptador de vista de datos privado _adapter
Adaptador de vista de datos privado
;
{
conseguir
{ // Creación de instancias retrasada
si (_adapter == nulo)
{
_adapter = nuevo DataViewAdapter((DataView)Fuente);
}
devolver _adaptador;
}
}
anulación pública del adaptador IDataSourceAdapter
{
obtener {return ViewAdapter;}
}
}
El tipo DataView y el tipo DataTable están tan estrechamente relacionados que puede tener sentido construir un DataAdapter genérico. De hecho, basta con agregar otro constructor que maneje el DataTable. Desafortunadamente, cuando los usuarios necesitan diferentes funcionalidades para manejar una DataTable, toda la clase debe ser reemplazada o heredada. Si construimos un nuevo Builder que usa el mismo IdataSourceAdapter, el usuario tiene más libertad para elegir cómo implementar el adaptador.
En el control de paginación, la operación de encontrar la clase de constructor adecuada se completa mediante una colección de tipo seguro.
Colección de adaptadores de clase pública: DiccionarioBase
{
cadena privada GetKey (Escriba clave)
{
tecla de retorno.NombreCompleto;
}
Colección de adaptadores públicos() {}
publicvoid Agregar (Escriba clave, valor de AdapterBuilder)
{
Dictionary.Add(GetKey(clave),valor);
}
publicbool contiene (escriba la clave)
{
return Dictionary.Contains(GetKey(clave));
}
publicvoid Eliminar (Escriba la clave)
{
Diccionario.Remove(GetKey(clave));
}
AdapterBuilder público esto[Escriba clave]
{
get{return (AdapterBuilder)Diccionario[GetKey(clave)];}
set{Diccionario[GetKey(clave)]=valor;}
}
}
AdapterCollection se basa en el tipo DataSource y DataSource se introduce inteligentemente a través de BoundControl_DataBound. La clave de índice utilizada aquí es el método Type.FullName, que garantiza la unicidad de la clave de índice de cada tipo. Al mismo tiempo, también asigna la responsabilidad de garantizar que solo haya un Constructor para cada tipo a AdapterCollection. Agregue la búsqueda del Builder al método BoundControl_DataBound y los resultados son los siguientes:
adaptadores públicos AdapterCollection
{
obtener {return _adapters;}
}
bool privado HasParentControlCalledDataBinding
{
obtener {return _builder! = nulo;}
}
privado vacío BoundControl_DataBound (remitente del objeto, System.EventArgs e)
{
si (HasParentControlCalledDataBinding) regresa;
Tipo tipo = remitente.GetType();
_datasource = type.GetProperty("Fuente de datos");
si (_datasource == nulo)
throw new NotSupportedException("El control de paginación requiere que el control de presentación contenga un DataSource.");
datos del objeto = _datasource.GetGetMethod().Invoke(remitente,null);
_builder = Adaptadores[data.GetType()];
si (_builder == nulo)
throw new NullReferenceException("El adaptador apropiado no está instalado para manejar el siguiente tipo de fuente de datos: "+data.GetType());
_builder.Source = datos;
ApplyDataSensitivityRules();
VincularParent();
RaiseEvent(Actualización de datos,esto);
}
El método BoundControl_DataBound usa HasParentControlCalledDataBinding para verificar si se ha creado el Generador. Si es así, ya no realizará la operación de encontrar el Generador apropiado. La inicialización de la tabla Adaptadores se realiza en el constructor:
public Pager()
{
SelectedPager=nuevo System.Web.UI.WebControls.Style();
UnselectedPager = nuevo System.Web.UI.WebControls.Style();
_adapters = nueva Colección de Adaptadores();
_adapters.Add(typeof(DataTable),nuevo DataTableAdapterBuilder());
_adapters.Add(tipode(DataView),nuevo DataViewAdapterBuilder());
}
El último método a implementar es BindParent, que se utiliza para procesar y devolver datos.
vacío privado BindParent()
{
_datasource.GetSetMethod().Invoke(BoundControl,
nuevo objeto[]{_builder.Adapter.GetPaggedData(StartRow,ResultsToShow*CurrentPage)});
}
Este método es muy simple, porque el procesamiento de datos lo realiza realmente el Adaptador. Una vez completado este proceso, usaremos la API de Reflection nuevamente, pero esta vez para configurar la propiedad DataSource del control de presentación.
3. Diseño de interfaz
Hasta ahora, las funciones principales del control de paginación casi se han implementado, pero si faltan métodos de presentación apropiados, el control de paginación no será muy útil.
Para separar efectivamente el método de presentación de la lógica del programa, la mejor manera es usar plantillas o, para ser más específicos, usar la interfaz Itemplate. De hecho, Microsoft comprende claramente el poder de las plantillas y las utiliza en casi todas partes, incluso en el propio analizador de páginas. Desafortunadamente, las plantillas no son un concepto tan simple como algunas personas piensan y lleva algún tiempo comprender realmente su esencia. Afortunadamente, hay mucha información en esta área, por lo que no entraré en detalles aquí. De regreso al control de paginación, tiene cuatro botones: página de inicio, página anterior, página siguiente, última página y por supuesto el número de cada página. Los cuatro botones de navegación se seleccionan de la clase ImageButton en lugar de la clase LinkButton. Desde una perspectiva de diseño web profesional, los botones gráficos son obviamente más útiles que los enlaces monótonos.
Botón de imagen público Primer botón {get {return First;}}
botón de imagen público Último botón {get {return Last;}}
botón de imagen público botón anterior {get {return anterior;}}
public ImageButton NextButton{get {return Next;}}
Los números de página se construyen dinámicamente porque dependen de la cantidad de registros en la fuente de datos y la cantidad de registros que se muestran en cada página. El número de página se agregará a un Panel y los diseñadores web pueden usar el Panel para especificar dónde mostrar el número de página. El proceso de creación de números de página se analizará en detalle más adelante. Ahora debemos proporcionar una plantilla para el control de paginación para que los usuarios puedan personalizar la apariencia del control de paginación.
[Contenedor de plantilla (tipo de (Contenedor de diseño))]
Diseño de plantilla I pública
{
obtener {return (_layout;}
establecer{_layout =valor;}
}
clase pública LayoutContainer:Control,INamingContainer
{
contenedor de diseño público()
{this.ID = "Página";}
}
La clase LayoutContainer proporciona un contenedor para plantillas. En términos generales, siempre es bueno agregar una ID personalizada al contenedor de plantillas, lo que evitará problemas al manejar eventos y realizar llamadas a páginas. El siguiente diagrama UML describe el mecanismo de presentación del control de paginación.
Figura 5
El primer paso para crear una plantilla es definir el diseño en la página aspx:
<DISPOSICIÓN>
<asp:ImageButton id="Primero" Runat="servidor" imageUrl="play2L_dis.gif"
Texto alternativo="Inicio"></asp:ImageButton>
<asp:ImageButton id="Anterior" Runat="servidor" imageUrl="play2L.gif"
AlternateText="Página anterior"></asp:ImageButton>
<asp:ImageButton id="Siguiente" Runat="servidor" imageUrl="play2.gif"
AlternateText="Página siguiente"></asp:ImageButton>
<asp:ImageButton id="Último" Runat="servidor" imageUrl="play2_dis.gif"
AlternateText="Última página"></asp:ImageButton>
<asp:Panel id="Buscapersonas" Runat="servidor"></asp:Panel>
</LAYOUT>
Este ejemplo de diseño no contiene ningún elemento de formato, como tablas, etc. Por supuesto, las aplicaciones reales pueden (y deben) agregar elementos de formato; consulte más instrucciones más adelante.
La interfaz Itemplate solo proporciona un método InstantiateIn, que analiza la plantilla y vincula el contenedor.
vacío privado InstantiateTemplate()
{
_contenedor = nuevo LayoutContainer();
Diseño.InstantiateIn(_container);
Primero = (ImageButton)_container.FindControl("Primero");
Anterior = (ImageButton)_container.FindControl("Anterior");
Siguiente = (ImageButton)_container.FindControl("Siguiente");
Último = (ImageButton)_container.FindControl("Último");
Titular = (Panel)_container.FindControl("Buscapersonas");
this.First.Click += nuevo System.Web.UI.ImageClickEventHandler(this.First_Click);
this.Last.Click += nuevo System.Web.UI.ImageClickEventHandler(this.Last_Click);
this.Next.Click += nuevo System.Web.UI.ImageClickEventHandler(this.Next_Click);
this.Previous.Click += nuevo System.Web.UI.ImageClickEventHandler(this.Previous_Click);
}
Lo primero que hace el método InstatiateTemplate del control es crear una instancia de la plantilla, es decir, llamar a Layout.InstantiateIn(_container). Un contenedor es en realidad un tipo de control y su uso es similar al de otros controles. El método InstantiateTemplate utiliza esta función para encontrar los cuatro botones de navegación y el Panel utilizado para contener el número de página. Los botones de navegación se encuentran por sus ID. Esta es una pequeña restricción en los controles de paginación: los botones de navegación deben tener ID especificadas, que son Primero, Anterior, Siguiente y Último. Además, la ID del Panel debe ser Buscapersonas, de lo contrario no será así. encontró. Desafortunadamente, este parece ser el mejor enfoque para el mecanismo de presentación que hemos elegido, pero esperamos que, con la documentación adecuada, esta pequeña limitación no cause ningún problema. Otra alternativa es dejar que cada botón herede de la clase ImageButton, definiendo así un nuevo tipo, dado que cada botón es de un tipo diferente, se puede implementar una búsqueda recursiva en el contenedor para encontrar varios botones específicos, eliminando la necesidad de usar el ID del botón; atributo.
Después de encontrar los cuatro botones, vincule a ellos los controladores de eventos apropiados. Aquí se debe tomar una decisión importante: cuándo llamar a InstantiateTemplate. Generalmente, este tipo de método debe llamarse en el método CreateChildControls, porque el propósito principal del método CreateChildControls es este tipo de tarea de crear controles secundarios. Dado que el control de paginación nunca modifica sus controles secundarios, no necesita la funcionalidad proporcionada por CreateChildControls para modificar el estado de visualización en función de algún evento. Cuanto más rápido se muestre el control secundario, mejor, por lo que el lugar ideal para llamar al método InstantiateTemplate es el evento OnInit.
anulación protegida anulación OnInit (EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += nuevo EventHandler(BoundControl_DataBound);
InstanciarTemplate();
Controles.Add(_container);
base.OnInit(e);
}
Además de llamar al método InstantiateTemplate, el método OnInit también tiene otra tarea importante: agregar el contenedor al control de paginación. Si no agrega el contenedor a la colección de controles del buscapersonas, la plantilla no se mostrará porque nunca se llamará al método Render.
Las plantillas también se pueden definir mediante programación implementando la interfaz Itemplate. Además de ser una medida para aumentar la flexibilidad, esta característica también puede proporcionar una plantilla predeterminada para usar cuando el usuario no proporciona una plantilla a través de una página aspx.
clase pública DefaultPagerLayout: ITemplate
{
botón de imagen privado Siguiente;
botón de imagen privado primero;
botón de imagen privado último;
Botón de imagen privado Anterior;
Buscapersonas de panel privado;
público DefaultPagerLayout();
{
Siguiente = nuevo ImageButton();
Primero = nuevo ImageButton();
Último = nuevo ImageButton();
Anterior = nuevo ImageButton();
Buscapersonas = nuevo Panel();
Next.ID="Siguiente"; Next.AlternateText="Página siguiente";Next.ImageUrl="play2.gif";
First.ID="Primero"; Primero.AlternateText="Inicio";First.ImageUrl="play2L_dis.gif";
Last.ID = "Último"; Last.AlternateText = "Última página" Last.ImageUrl="play2_dis.gif";
Previous.ID="Anterior"; Previous.AlternateText="Página anterior";Previous.ImageUrl="play2L.gif";
Buscapersonas.ID="Buscapersonas";
}
public void InstantiateIn (control de control)
{
control.Controls.Clear();
Tabla tabla = nueva Tabla();
tabla.BorderWidth = Unidad.Pixel(0);
tabla.CellSpacing= 1;
tabla.CellPadding =0;
fila TableRow = nueva TableRow();
fila.VerticalAlign = VerticalAlign.Top;
tabla.Rows.Add(fila);
Celda TableCell = nueva TableCell();
celda.HorizontalAlign = HorizontalAlign.Right;
celda.VerticalAlign = VerticalAlign.Middle;
cell.Controls.Add(Primero);
cell.Controls.Add(Anterior);
fila.Celdas.Agregar(celda);
celda = nueva TableCell();
cell.HorizontalAlign= HorizontalAlign.Center;
cell.Controls.Add(Buscapersonas);
fila.Celdas.Agregar(celda);
celda = nueva TableCell();
celda.VerticalAlign = VerticalAlign.Middle;
cell.Controls.Add(Siguiente);
cell.Controls.Add(Último);
fila.Celdas.Agregar(celda);
control.Controles.Agregar(tabla);
}
}
DefaultPagerLayout proporciona todos los elementos de navegación mediante programación y los agrega a la página aspx, pero esta vez los elementos de navegación tienen el formato de tablas HTML estándar. Ahora, si el usuario no proporciona una plantilla de presentación, el programa proporcionará automáticamente una plantilla predeterminada.
[Contenedor de plantilla (tipo de (Contenedor de diseño))]
Diseño de plantilla I pública
{
get{return (_layout == null)? nuevo DefaultPagerLayout():_layout;}
establecer{_layout =valor;}
}
Echemos un vistazo al proceso de generación de cada número de página. El control de paginación primero debe determinar algunos valores de propiedad y utilizar estos valores de propiedad para determinar cuántos números de página diferentes se generarán.
public intPágina actual
{
conseguir
{
cadena cur = (cadena)ViewState["Página actual"];
return (cur == cadena.Empty || cur ==null)?
}
colocar
{
ViewState["CurrentPage"] = valor.ToString();}
}
público int PagersToShow
{
obtener {return _results;}
establecer{_resultados = valor;}
}
público int ResultsToShow
{
obtener {return _resultsperpage;}
establecer{_resultsperpage = valor;}
}
CurrentPage en realidad guarda la página actual en el ViewState del número de página. Las propiedades definidas por el método PagersToShow permiten al usuario especificar cuántas páginas mostrar, mientras que las propiedades definidas por ResultsToShow le permiten especificar en cuántos registros mostrar. cada página. El valor predeterminado es 10.
NumberofPagersToGenerate devuelve el número actual de números de página que deben generarse.
secuencia de paginación int privada
{
conseguir
{
devolver Convert.ToInt32
(Math.Ceiling((doble)CurrentPage/(doble)PagersToShow));}
}
privado int NumberOfPagersToGenerate
{
obtener {return PagerSequence*PagersToShow;}
}
privado int TotalPagesToShow
{
get{return Convert.ToInt32(Math.Ceiling((double)TotalResults/(double)_resultsperpage));}
}
resultados totales públicos int
{
obtener {return _builder.Adapter.TotalCount;}
}
El método TotalPagesToShow devuelve el número total de páginas que se mostrarán, ajustado por la propiedad ResultsToShow preestablecida del usuario.
Aunque ASP.NET define algunos estilos predeterminados, es posible que no resulten muy prácticos para los usuarios de controles de paginación. Los usuarios pueden ajustar la apariencia del control de paginación mediante estilos personalizados.
Estilo público UnSelectedPagerStyle {get {return UnselectedPager;}}
Estilo público SelectedPagerStyle {get {return SelectedPager;}}
UnSelectedPagerStyle proporciona el estilo utilizado cuando no se selecciona el número de página, y SelectedPagerStyle proporciona el estilo utilizado cuando se selecciona el número de página.
vacío privado GeneratePagers (control WebControl)
{
control.Controls.Clear();
int buscapersonas = (PagerSequence-1)* PagersToShow +1
para (;pager<=NumberOfPagersToGenerate && pager<=TotalPagesToShow;pager++)
{
Enlace LinkButton = nuevo LinkButton();
enlace.Texto = buscapersonas.ToString();
enlace.ID = buscapersonas.ToString();
link.Click += new EventHandler(this.Pager_Click);
si (enlace.ID.Equals(CurrentPage.ToString()))
enlace.MergeStyle(SelectedPagerStyle);
demás
enlace.MergeStyle(UnSelectedPagerStyle);
control.Controls.Add(enlace);
control.Controls.Add(new LiteralControl(" "));
}
}
vacío privado GeneratePagers()
{
GenerarPagers(titular);
}
El método GeneratePagers crea dinámicamente todos los números de página, que son botones de tipo LinkButton. Los atributos de etiqueta e ID de cada número de página se asignan mediante un bucle y, al mismo tiempo, el evento de clic se vincula al controlador de eventos apropiado. Finalmente, el número de página se agrega a un control contenedor, en este caso, un objeto Panel. El ID del botón sirve para identificar qué botón activó el evento de clic. La siguiente es la definición de controlador de eventos:
privado void Pager_Click (remitente del objeto, System.EventArgs e)
{
Botón LinkButton = (LinkButton) remitente;
PáginaActual = int.Parse(botón.ID);
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PaggedEventInvoker.Pager));
Actualizar();
}
privado vacío Next_Click (remitente del objeto, System.Web.UI.ImageClickEventArgs e)
{
si (Página actual<TotalPagesToShow)
Página actual++;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PaggedEventInvoker.Next));
Actualizar();
}
privado vacío Previous_Click (remitente del objeto, System.Web.UI.ImageClickEventArgs e)
{
si (Página actual > 1)
Página actual--;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PaggedEventInvoker.Previous));
Actualizar();
}
vacío privado First_Click (remitente del objeto, System.Web.UI.ImageClickEventArgs e)
{
Página actual = 1;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PaggedEventInvoker.First));
Actualizar();
}
privado vacío Last_Click (remitente del objeto, System.Web.UI.ImageClickEventArgs e)
{
PáginaActual = TotalPagesToShow;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PaggedEventInvoker.Last));
Actualizar();
}
Estos controladores de eventos son similares en que primero cambian la página actual del control de paginación y luego actualizan el control vinculado.
Actualización de vacío privado()
{
si (!HasParentControlCalledDataBinding) regresa;
AplicarDataSensitivityRules();
VincularParent();
BoundControl.DataBind();
}
Primero, el control de paginación comprueba si los adaptadores necesarios se han inicializado llamando al método HasParentControlCalledDataBinding. Si es así, aplique las reglas señaladas anteriormente para ajustar automáticamente los controles según las condiciones de visualización de datos al control actual. Estas reglas hacen que el control de paginación se comporte de manera diferente según las diferentes condiciones de los datos en BoundControl. Aunque estas reglas están controladas internamente por el control de paginación, se pueden sacar fácilmente del control usando el modo de estado [GoF] cuando sea necesario.
bool público IsDataSensitive
{
obtener {return _isdataSENSITIVE;}
establecer{_isdataSENSITIVE = valor;}
}
bool privado IsPagerVisible
{
obtener {return (TotalPagesToShow! = 1) && IsDataSensitive;}
}
bool privado IsPreviousVisible
{
conseguir
{
retorno (!IsDataSensitive)? verdadero:
(Página actual! = 1);
}
}
bool privado IsNextVisible
{
conseguir
{
retorno (!IsDataSensitive)? verdadero:
(Página actual! = TotalPagesToShow);
}
}
vacío privado ApplyDataSensitivityRules()
{
PrimerBotón.Visible = EsPrevioVisible;
BotónAnterior.Visible = EsPrevioVisible;
ÚltimoBotón.Visible = EsSiguienteVisible;
SiguienteButton.Visible = EsNextVisible;
si (IsPagerVisible) GeneratePagers();
}
El método ApplyDataSensitivityRules implementa reglas predefinidas como IsPagerVisible, IsPreviousVisible e IsNextVisible. De forma predeterminada, el control de paginación tendrá estas reglas habilitadas, pero el usuario puede desactivarlas configurando la propiedad IsDataSensitive.
Hasta ahora, la parte de visualización del control de paginación se ha diseñado básicamente. El último trabajo restante que queda es proporcionar varios controladores de eventos para que los usuarios puedan realizar los ajustes necesarios cuando se produzcan varios eventos de control de paginación.
delegado público void PageDelegate (remitente del objeto, PageChangedEventArgs e);
enumeración pública PagedEventInvoker {Siguiente, Anterior, Primero, Último, Buscapersonas}
clase pública PageChangedEventArgs: EventArgs
{
nueva página privada int;
invocador de enumeración privada
PageChangedEventArgs pública (int nueva página): base ()
{
this.newpage = nueva página;
}
PageChangedEventArgs público (int nueva página, invocador PagedEventInvoker)
{
this.newpage = nueva página;
this.invoker = invocador;
}
public int NuevaPágina {get{return newpage;}}
public Enum EventInvoker{get{return invoker;}}
}
Dado que el control de paginación necesita devolver parámetros de eventos personalizados, definimos una clase PageChangedEventArgs dedicada. La clase PageChangedEventArgs devuelve el tipo PagedEventInvoker, que es un enumerador de los controles que pueden desencadenar el evento. Para manejar parámetros de eventos personalizados, definimos un nuevo delegado, PageDelegate. El evento se define de la siguiente forma:
evento público PageDelegate PageChanged;
evento público EventHandler DataUpdate
Cuando un evento no tiene un detector de eventos correspondiente, ASP.NET generará una excepción. El control de paginación define los siguientes métodos RaiseEvent.
vacío privado RaiseEvent (EventHandler e, remitente del objeto)
{
this.RaiseEvent(e,esto,nulo);
}
privado vacío RaiseEvent (EventHandler e, remitente del objeto, argumentos PageChangedEventArgs)
{
si(e!=nulo)
{
e(remitente,argumentos);
}
}
RaiseEvent vacío privado (PageDelegate e, remitente del objeto)
{
this.RaiseEvent(e,esto,nulo);
}
privado vacío RaiseEvent (PageDelegate e, remitente del objeto, argumentos PageChangedEventArgs)
{
si(e!=nulo)
{
e(remitente,argumentos);
}
}
Los manejadores de eventos ahora pueden activar eventos llamando a los métodos de EventEvent individuales.
4. Ejemplos de aplicación
En este punto, el diseño del control de la paginación se ha completado y se puede utilizar oficialmente. Para usar el control de la paginación, simplemente uniéndolo a un control de presentación.
<ASP: Repeater ID = "Repeater" Runat = "Server">
<Plantilla de artículo>
Columna 1:
<%# Convert.ToString (databinder.eval (contenedor.dataitem, "column1"))%>
<br>
Columna 2:
<%# Convert.ToString (databinder.eval (contenedor.dataitem, "column2"))%>
<br>
Columna 3:
<%# Convert.ToString (databinder.eval (contenedor.dataitem, "column3"))%>
<br>
<hora>
</Plantilla de elemento>
</ASP: repetidor >
< CC1: Pager ID = "Pager" ResultShowow = "2" Runat = "Server" bindTocontrol = "Repetidor" >
< SelectedPagerStyle BackColor = "Yellow" />
</CC1: Pager >
La página ASPX anterior vincula el control de paginación a un control de repetidor, establece el número de registros que se muestran en cada página a 2, el color del número de página seleccionado es amarillo y usa el diseño predeterminado. Como se muestra en la Figura 1. A continuación se muestra otro ejemplo, que une el control de paginación a una datagrid, como se muestra en la Figura 2.
< ASP: DataGrid ID = "Grid" Runat = "Server" ></ASP: DataGrid >
< CC1: Pager ID = "PagerGrid" ResultShowow = "2" runat = "Server" bindTocontrol = "Grid" >
< SelectedPagerStyle BackColor = "Red" ></SelectedPagerStyle >
< Diseño >
< ASP: ImageButton id = "First" Runat = "Server" ImageUrl = "Play2L_DIS.GIF" Alternatetext = "Home" ></Asp: ImageButton >
< ASP: ImageButton id = "anterior" runat = "servidor" imageUrl = "play2l.gif" alternatetext = "página anterior" ></asp: imageButton >
< ASP: ImageButton ID = "Next" Runat = "Server" ImageUrl = "Play2.gif" AlternatExtext = "Página siguiente" ></ASP: ImageButton >
< ASP: ImageButton ID = "Last" Runat = "Server" ImageUrl = "Play2_dis.gif" Alternatetext = "Last Page" ></ASP: ImageButton >
< ASP: Panel ID = "Pager" Runat = "Server" ></ASP: Panel >
</diseño >
</CC1: Pager >
La prueba muestra que el control de la paginación no depende de los controles de presentación específicos. El ejemplo completo.
Aunque aprender a desarrollar controles web personalizados no es una tarea fácil, los beneficios de dominar esta habilidad son evidentes. Times.
http://www.cnblogs.com/niit007/archive/2006/08/13/475501.html