Практически для всех веб-приложений представления данных организация способа отображения данных и предотвращение путаницы у пользователей является одной из основных целей. Отображение 20 записей на странице, безусловно, приемлемо, но отображение 10 000 записей на странице может легко вызвать неудобства у пользователей. Разделение данных на несколько страниц для отображения, то есть разбивка данных по страницам, является наиболее распространенным способом решения таких проблем.
1. Обзор
Сам по себе ASP.NET предоставляет только один элемент управления, поддерживающий разбиение на страницы, а именно элемент управления разбиением на страницы DataGrid. Однако он больше подходит для использования в средах интрасети. Для сред Интернета функции, предоставляемые элементом управления разбиением на страницы DataGrid, похоже, не поддерживаются. этого будет достаточно для создания гибкого веб-приложения. Одна из причин заключается в том, что элемент управления DataGrid накладывает ограничения на то, где веб-дизайнеры могут размещать элементы управления страницами, а также на их внешний вид. Например, элемент управления DataGrid не допускает вертикального размещения элементов управления страницами. Еще один элемент управления, который может использовать преимущества технологии разбиения по страницам, — это Повторитель. Веб-разработчики могут использовать элемент управления Повторитель для быстрой настройки метода отображения данных, но функция разбиения по страницам требует, чтобы разработчики реализовали ее самостоятельно. Источники данных постоянно меняются, а методы представления данных сильно различаются. Очевидно, было бы пустой тратой времени настраивать элементы управления разбиением на страницы для этих меняющихся условий. Создание универсального элемента управления страницами, не ограничивающегося конкретными элементами управления представлением, значительно поможет сэкономить время.
Превосходный универсальный элемент управления данными не только обеспечивает регулярные функции пейджинга, но также может:
⑴ Предоставьте кнопки навигации по страницам «Домашняя страница», «Предыдущая страница», «Следующая страница» и «Последняя страница».
⑵ Отрегулируйте его статус в соответствии с ситуацией отображения данных, то есть он имеет чувствительность к данным. Если элемент управления разбиением по страницам настроен на отображение 10 записей на странице, но на самом деле их всего 9, то элемент управления разбиением на страницы не должен отображаться, когда данные разделены на несколько страниц для отображения, «Главная» и «Верхняя часть»; первая страница. Кнопка «Страница» не должна отображаться, а также не должны отображаться кнопки «Следующая страница» и «Последняя страница» последней страницы.
⑶ Невозможно полагаться на определенные элементы управления отображением данных.
⑷ Возможность адаптации к различным существующим и будущим источникам данных.
⑸ Режим отображения должен легко настраиваться и легко интегрироваться в различные приложения.
⑹ Когда пейджинг будет готов, напомните об этом другим элементам управления.
⑺ Даже неопытные веб-дизайнеры смогут без труда использовать его.
⑻ Предоставление атрибутивных данных о пейджинговой информации.
В настоящее время на рынке имеются коммерческие средства управления, обеспечивающие вышеуказанные функции, но все они дороги. Для многих разработчиков идеальным выбором является создание универсального элемента управления подкачкой.
На рис. 1 показан рабочий интерфейс универсального элемента управления разбиением на страницы в этой статье, в котором для отображения используется элемент управления Повторитель. Элемент управления страницами состоит из двух типов компонентов: четырех кнопок навигации и набора ссылок на номера страниц.
Пользователи могут легко изменить элементы управления отображением и изменить внешний вид самого элемента управления страницами. Например, элемент управления отображением, который взаимодействует с элементом управления разбиением на страницы, заменяется элементом управления DataGrid, а ссылка на номер страницы и четыре кнопки навигации отображаются в двух строках.
ASP.NET поддерживает три способа создания пользовательских веб-элементов управления: пользовательские элементы управления, составные элементы управления и настраиваемые элементы управления. Название третьего типа элемента управления (пользовательский элемент управления) легко вводит в заблуждение. Фактически, все три элемента управления следует рассматривать как настраиваемые элементы управления. Разница между составными элементами управления и так называемыми пользовательскими элементами управления Microsoft заключается в том, что для первого требуется метод CreateChildControls(). Метод CreateChildControls() позволяет элементу управления перерисовываться на основе определенных событий. Для универсального пейджера в этой статье мы будем использовать составной элемент управления.
Следующая диаграмма последовательности UML описывает общий механизм универсального управления подкачкой.
Хотя наша цель — сделать универсальный элемент управления подкачкой независимым от элемента управления, представляющего данные, очевидно, что должен быть какой-то способ для элемента управления подкачкой получить доступ к данным. Каждый элемент управления, наследуемый от класса Control, предоставляет событие DataBinding. Мы регистрируем сам пейджер в качестве прослушивателя события DataBinding, чтобы пейджер мог узнавать о данных и изменять их. Поскольку все элементы управления, наследуемые от класса Control, имеют это событие DataBinding, элемент управления пейджером достигает цели не полагаться на конкретный элемент управления представлением данных — другими словами, элемент управления пейджером может быть привязан ко всем элементам управления, производным от класса Control. То есть его можно привязать практически ко всем веб-элементам управления.
2. Основные функции.
Когда элемент управления представлением запускает событие DataBinding, элемент управления разбиением на страницы может получить свойство DataSource. К сожалению, Microsoft не предоставляет интерфейсы, которые реализуют все классы привязки данных, такие как IdataSourceProvider, и не все элементы управления, наследуемые от класса Control или WebControl, имеют свойство DataSource, поэтому нет смысла повышать преобразование до класса Control, это единственный возможный вариант. Способ заключается в непосредственном управлении свойством DataSoruce через Reflection API. Прежде чем обсуждать методы обработчика событий, следует отметить, что для регистрации обработчика событий необходимо сначала получить ссылку на элемент управления представлением. Элемент управления подкачкой предоставляет простое строковое свойство BindToControl:
общедоступная строка BindToControl
{
получать
{
если (_bindcontrol == ноль)
throw new NullReferenceException("Перед использованием элемента управления разбиением на страницы привяжите его к элементу управления, установив свойство BindToControl.");
вернуть _bindcontrol;}
установить {_bindcontrol = значение;}
}
Этот метод очень важен, поэтому лучше выдавать более четкое сообщение вместо стандартного исключения NullReferenceException. В методе OnInit элемента управления страницами мы разрешаем ссылку на элемент управления представлением. В этом примере следует использовать обработчик событий OnInit (а не конструктор), чтобы гарантировать, что на JIT-скомпилированной странице aspx установлен BindToControl.
защищенное переопределение void OnInit (EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += новый EventHandler(BoundControl_DataBound);
base.OnInit(е);
...
}
Операция поиска элемента управления представлением завершается поиском в родительском элементе управления страницами. Здесь родительским элементом является сама страница. Использовать Parent таким образом опасно. Например, если элемент управления разбиением на страницы встроен в другой элемент управления, например в элемент управления Table, ссылка Parent на самом деле будет ссылкой на элемент управления Table. Поскольку метод FindControl выполняет поиск только в текущей коллекции элементов управления, поиск невозможен, если элемент управления представлением не находится в коллекции. Более безопасный подход — рекурсивный поиск по коллекции элементов управления до тех пор, пока не будет найден целевой элемент управления.
Найдя BoundControl, мы регистрируем элемент управления подкачкой в качестве прослушивателя события DataBinding. Поскольку элемент управления подкачкой работает с источником данных, важно, чтобы этот обработчик событий был последним в цепочке вызовов. Однако, пока элемент управления представлением регистрирует обработчик событий DataBinding в обработчике событий OnInit (поведение по умолчанию), проблем при работе с источником данных не возникнет.
Обработчик событий DataBound отвечает за получение свойства DataSource элемента управления представлением.
частная пустота BoundControl_DataBound (отправитель объекта, System.EventArgs e)
{
если (HasParentControlCalledDataBinding) возврат;
Тип типа = sender.GetType();
_datasource = type.GetProperty("Источник данных");
если (_datasource == ноль)
throw new NotSupportedException("Элемент управления страницами требует, чтобы элемент управления презентацией содержал источник данных.");
данные объекта = _datasource.GetGetMethod().Invoke(отправитель,ноль);
_builder = Адаптеры[data.GetType()];
если (_builder == ноль)
throw new NullReferenceException("Не установлен соответствующий адаптер для обработки следующего типа источника данных: "+data.GetType());
_builder.Source = данные;
ApplyDataSensitivityRules();
БиндРодитель();
RaiseEvent (DataUpdate, это);
}
В DataBound мы пытаемся получить свойство DataSource через Reflection API, а затем возвращаем ссылку на фактический источник данных. Теперь, когда источник данных известен, элемент управления подкачкой также должен знать, как работать с источником данных. Чтобы сделать управление пейджингом независимым от конкретного элемента управления презентацией, задача значительно усложняется. Однако создание зависимости управления подкачкой от конкретного источника данных противоречит цели разработки гибкого управления подкачкой. Нам необходимо использовать подключаемую архитектуру, чтобы гарантировать, что элемент управления подкачкой может обрабатывать различные источники данных, будь то источник данных, предоставляемый .NET, или пользовательский источник данных.
Чтобы обеспечить надежную масштабируемую подключаемую архитектуру, мы создадим решение, используя шаблон [GoF] Builder.
Рис. 4.
Интерфейс IDataSourceAdapter определяет самые основные элементы, необходимые для управления подкачкой для работы с данными, что эквивалентно «заглушке».
publicinterface IDataSourceAdapter
{
интервал TotalCount {получить;}
объект GetPagedData(int start,int end);
}
Свойство TotalCount возвращает общее количество элементов, содержащихся в источнике данных, до обработки данных, а метод GetPagedData возвращает подмножество исходных данных. Например: если источником данных является массив, содержащий 20 элементов, отобразится элемент управления разбиением на страницы. данные представляют собой 10 элементов на странице elements, то подмножество элементов на первой странице — это элементы массива 0–9, а подмножество элементов на второй странице — элементы массива 10–19. DataViewAdapter предоставляет плагин типа DataView:
внутренний класс DataViewAdapter:IDataSourceAdapter
{
частный DataView _view
внутренний DataViewAdapter (представление DataView);
{
_view = просмотр;
}
public int TotalCount
{
получить {возврат (_view == null) 0: _view.Table.Rows.Count;}
}
общедоступный объект GetPagedData (начало int, конец int)
{
Таблица DataTable = _view.Table.Clone();
for (int i = start;i<=end && i<= TotalCount;i++)
{
table.ImportRow(_view[i-1].Row);
}
возвратный стол;
}
}
DataViewAdapter реализует метод GetPagedData класса IDataSourceAdapter, который клонирует исходный DataTable и импортирует данные из исходного DataTable в новый DataTable. Видимость этого класса намеренно установлена на внутреннюю, чтобы скрыть детали реализации от веб-разработчиков и предоставить более простой интерфейс через класс Builder.
публичный абстрактный класс AdaptBuilder
{
частный объект _source
частный недействительный CheckForNull();
{
if (_source == null) throw new NullReferenceException("Необходимо указать легальный источник данных");
}
Публичный виртуальный объект Источник
{
получать
{
ПроверитьФорНулл();
вернуть _источник;}
набор
{
_источник = значение;
ПроверитьФорНулл();
}
}
общедоступный абстрактный адаптер IDataSourceAdapter {get;}
}
Абстрактный класс AdaptorBuilder предоставляет более управляемый интерфейс для типа IdataSourceAdapter. Благодаря повышенному уровню абстракции нам больше не нужно напрямую использовать IdataSourceAdapter. В то же время AdapterBuilder также предоставляет инструкции для выполнения предварительной обработки перед разбиением на страницы данных. Кроме того, этот Builder также делает фактический класс реализации, такой как DataViewAdapter, прозрачным для пользователей элемента управления разбиением на страницы:
открытый класс DataTableAdapterBuilder:AdapterBuilder
{
частный DataViewAdapter _adapter
частный DataViewAdapter ViewAdapter
;
{
получать
{
если (_adapter == ноль)
{
Таблица DataTable = (DataTable) Источник;
_adapter = новый DataViewAdapter(table.DefaultView);
}
вернуть _адаптер;
}
}
общедоступное переопределение адаптера IDataSourceAdapter
{
получать
{
вернуть ViewAdapter;
}
}
}
открытый класс DataViewAdapterBuilder:AdapterBuilder
{
частный DataViewAdapter _adapter
частный DataViewAdapter ViewAdapter
;
{
получать
{ // Отложенное создание экземпляра
если (_adapter == ноль)
{
_adapter = новый DataViewAdapter((DataView)Source);
}
вернуть _адаптер;
}
}
общедоступное переопределение адаптера IDataSourceAdapter
{
получить {вернуть ViewAdapter;}
}
}
Тип DataView и тип DataTable настолько тесно связаны, что может иметь смысл создать универсальный DataAdapter. На самом деле достаточно просто добавить еще один конструктор, который обрабатывает DataTable. К сожалению, когда пользователям нужны другие функциональные возможности для работы с DataTable, необходимо заменить или унаследовать весь класс. Если мы создадим новый Builder, который использует тот же IdataSourceAdapter, у пользователя будет больше свободы в выборе способа реализации адаптера.
В страничном управлении операция поиска соответствующего класса Builder завершается типобезопасной коллекцией.
общедоступный класс AdaptCollection:DictionaryBase
{
частная строка GetKey (ключ типа)
{
вернуть ключ.ПолноеИмя;
}
общественный адаптерколлекция () {}
publicvoid Add (ключ типа, значение AdapterBuilder)
{
Dictionary.Add(GetKey(ключ),значение);
}
publicbool Содержит (ключ типа)
{
return Dictionary.Contains(GetKey(ключ));
}
publicvoid Удалить (Введите ключ)
{
Dictionary.Remove(GetKey(ключ));
}
public AdaptBuilder this [Введите ключ]
{
get{return (AdapterBuilder)Dictionary[GetKey(key)];}
set{Dictionary[GetKey(key)]=значение;}
}
}
AdaptorCollection опирается на тип DataSource, а DataSource хитроумно вводится через BoundControl_DataBound. В качестве индексного ключа здесь используется метод Type.FullName, который обеспечивает уникальность индексного ключа каждого типа. В то же время он также возлагает на AdaptorCollection ответственность за наличие только одного Builder для каждого типа. Добавьте поиск Builder к методу BoundControl_DataBound, и результаты будут следующими
:
{
получить {вернуть _адаптеры;}
}
Private bool HasParentControlCalledDataBinding
{
получить {вернуть _builder! = ноль;}
}
Private void BoundControl_DataBound (отправитель объекта, System.EventArgs e)
{
если (HasParentControlCalledDataBinding) возврат;
Тип типа = sender.GetType();
_datasource = type.GetProperty("Источник данных");
если (_datasource == ноль)
throw new NotSupportedException("Элемент управления страницами требует, чтобы элемент управления презентацией содержал источник данных.");
данные объекта = _datasource.GetGetMethod().Invoke(отправитель,ноль);
_builder = Адаптеры[data.GetType()];
если (_builder == ноль)
throw new NullReferenceException("Не установлен соответствующий адаптер для обработки следующего типа источника данных: "+data.GetType());
_builder.Source = данные;
ApplyDataSensitivityRules();
БиндРодитель();
RaiseEvent (DataUpdate, это);
}
Метод BoundControl_DataBound использует HasParentControlCalledDataBinding для проверки того, был ли создан Builder. Если да, то он больше не будет выполнять операцию поиска соответствующего Builder. Инициализация таблицы адаптеров выполняется в конструкторе:
public Pager().
{
SelectedPager = новый System.Web.UI.WebControls.Style();
UnselectedPager = новый System.Web.UI.WebControls.Style();
_adapters = новый адаптерCollection ();
_adapters.Add(typeof(DataTable),новый DataTableAdapterBuilder());
_adapters.Add(typeof(DataView),новый DataViewAdapterBuilder());
}
Последний метод, который нужно реализовать, — это BindParent, который используется для обработки и возврата данных.
частная пустота BindParent()
{
_datasource.GetSetMethod().Invoke(BoundControl,
новый объект[]{_builder.Adapter.GetPagedData(StartRow,ResultsToShow*CurrentPage)});
}
Этот метод очень прост, поскольку обработку данных фактически выполняет адаптер. После завершения этого процесса мы снова воспользуемся API Reflection, но на этот раз для установки свойства DataSource элемента управления представлением.
3. Дизайн интерфейса
. На данный момент основные функции управления пейджингом почти реализованы, но при отсутствии соответствующих методов представления управление пейджингом не будет очень полезным.
Чтобы эффективно отделить метод представления от логики программы, лучше всего использовать шаблоны, а точнее, интерфейс Itemplate. На самом деле, Microsoft четко понимает силу шаблонов и использует их практически везде, даже в самом парсере страниц. К сожалению, шаблоны — это не такая простая концепция, как думают некоторые, и требуется некоторое время, чтобы по-настоящему понять ее суть. К счастью, информации в этой области очень много, поэтому я не буду здесь вдаваться в подробности. Возвращаясь к элементу управления страницами, он имеет четыре кнопки: домашняя страница, предыдущая страница, следующая страница, последняя страница и, конечно же, номер каждой страницы. Четыре кнопки навигации выбраны из класса ImageButton вместо класса LinkButton. С точки зрения профессионального веб-дизайна графические кнопки, очевидно, более полезны, чем монотонные ссылки.
public ImageButton FirstButton {получить {вернуться первым;}}
public ImageButton LastButton {get {return Last;}}
public ImageButtonПредыдущаяButton{получить {вернуть предыдущую;}}
public ImageButton NextButton{get {return Next;}}
Номера страниц создаются динамически, поскольку они зависят от количества записей в источнике данных и количества записей, отображаемых на каждой странице. Номер страницы будет добавлен на панель, и веб-дизайнеры смогут использовать панель, чтобы указать, где отображать номер страницы. Процесс создания номеров страниц будет подробно рассмотрен позже. Теперь нам нужно предоставить шаблон для элемента управления страницами, чтобы пользователи могли настраивать внешний вид элемента управления страницами.
[Контейнер шаблонов(typeof(LayoutContainer))]
общедоступный макет ITemplate
{
получить {вернуться (_layout;}
установить {_layout = значение;}
}
Открытый класс LayoutContainer:Control,INamingContainer
{
publicLayoutContainer()
{this.ID = "Страница";}
}
Класс LayoutContainer предоставляет контейнер для шаблонов. Вообще говоря, всегда полезно добавить в контейнер шаблона собственный идентификатор, что позволит избежать проблем при обработке событий и вызове страниц. Следующая диаграмма UML описывает механизм представления управления страницами.
Рис. 5.
Первым шагом в создании шаблона является определение макета на странице aspx:
<МАКЕТ>
<asp:Panel id="Pager" Runat="server"></asp:Panel>
</LAYOUT>
Этот пример макета не содержит никаких элементов формата, таких как таблицы и т. д. Конечно, реальные приложения могут (и должны) добавлять элементы формата, дополнительные инструкции см. ниже.
Интерфейс Itemplate предоставляет только один метод InstantiateIn, который анализирует шаблон и привязывает контейнер.
частная пустота InstantiateTemplate()
{
_container = новый LayoutContainer();
Layout.InstantiateIn(_container);
First = (ImageButton)_container.FindControl("Первый");
Предыдущий = (ImageButton)_container.FindControl("Предыдущий");
Далее = (ImageButton)_container.FindControl("Далее");
Последний = (ImageButton)_container.FindControl("Последний");
Holder = (Panel)_container.FindControl("Пейджер");
this.First.Click += новый System.Web.UI.ImageClickEventHandler(this.First_Click);
this.Last.Click += новый System.Web.UI.ImageClickEventHandler(this.Last_Click);
this.Next.Click += новый System.Web.UI.ImageClickEventHandler(this.Next_Click);
this.Previous.Click += новый System.Web.UI.ImageClickEventHandler(this.Previous_Click);
}
Первое, что делает метод InstatiateTemplate элемента управления, — это создает экземпляр шаблона, то есть вызывает Layout.InstantiateIn(_container). Контейнер на самом деле является своего рода элементом управления, и его использование аналогично другим элементам управления. Метод InstantiateTemplate использует эту функцию для поиска четырех кнопок навигации и панели, используемой для хранения номера страницы. Кнопки навигации находятся по их идентификаторам. Это небольшое ограничение для элементов управления перелистыванием: кнопки навигации должны иметь указанные идентификаторы: «Первый», «Предыдущий», «Следующий» и «Последний». Кроме того, идентификатор панели должен быть «Пейджер», иначе он не будет. найденный. К сожалению, это лучший подход для выбранного нами механизма представления, но мы надеемся, что при наличии надлежащей документации это незначительное ограничение не вызовет никаких проблем; Другая альтернатива — позволить каждой кнопке наследовать от класса ImageButton, тем самым определяя новый тип, поскольку каждая кнопка имеет другой тип, в контейнере можно реализовать рекурсивный поиск для поиска различных конкретных кнопок, что устраняет необходимость использования идентификатора кнопки; атрибут.
После того, как вы найдете четыре кнопки, привяжите к ним соответствующие обработчики событий. Здесь необходимо принять важное решение, а именно, когда вызывать InstantiateTemplate. Как правило, этот тип метода следует вызывать в методе CreateChildControls, поскольку основной целью метода CreateChildControls является задача такого типа по созданию дочерних элементов управления. Поскольку элемент управления разбиением на страницы никогда не изменяет свои дочерние элементы управления, ему не нужны функциональные возможности, предоставляемые CreateChildControls, для изменения состояния отображения на основе какого-либо события. Чем быстрее отображается дочерний элемент управления, тем лучше, поэтому идеальным местом для вызова метода InstantiateTemplate является событие OnInit.
защищенное переопределение void OnInit (EventArgs e)
{
_boundcontrol = Parent.FindControl(BindToControl);
BoundControl.DataBinding += новый EventHandler(BoundControl_DataBound);
InstantiateTemplate();
Controls.Add(_container);
base.OnInit(е);
}
Помимо вызова метода InstantiateTemplate, метод OnInit также выполняет еще одну важную задачу — добавление контейнера в элемент управления подкачки. Если вы не добавите контейнер в коллекцию элементов управления пейджера, шаблон не будет отображаться, поскольку метод Render никогда не будет вызываться.
Шаблоны также можно определять программно, реализуя интерфейс Itemplate. Эта функция не только является мерой повышения гибкости, но и может предоставить шаблон по умолчанию для использования, когда пользователь не предоставляет шаблон через страницу aspx.
общедоступный класс DefaultPagerLayout:ITemplate
{
частная кнопка изображения Далее;
частный ImageButton First;
частный ImageButton Last;
частная ImageButton Предыдущая;
частный пейджер панели
общедоступный DefaultPagerLayout();
{
Далее = новый ImageButton();
Первый = новый ImageButton();
Последний = новый ImageButton();
Предыдущий = новый ImageButton();
Пейджер = новая панель()
Next.ID="Далее"; Next.AlternateText="Следующая страница";Next.ImageUrl="play2.gif";
First.ID="First"; First.AlternateText="Home";First.ImageUrl="play2L_dis.gif";
Last.ID = "Последний"; Last.AlternateText = "Последняя страница"; Last.ImageUrl="play2_dis.gif";
Предыдущая.ID="Предыдущая"; Предыдущая.AlternateText="Предыдущая страница";Previous.ImageUrl="play2L.gif";
Пейджер.ID="Пейджер";
}
public void InstantiateIn (контроль управления)
{
control.Controls.Clear();
Таблица таблица = новая таблица();
таблица.BorderWidth = Unit.Pixel(0);
таблица.CellSpacing= 1;
таблица.CellPadding =0;
Строка TableRow = новая TableRow();
row.VerticalAlign = ВертикальноеВыравнивание.Верх;
таблица.Rows.Add(строка);
Ячейка TableCell = новая TableCell();
ячейка.HorizontalAlign = HorizontalAlign.Right;
ячейка.VerticalAlign = ВертикальноеВыравнивание.Средний;
ячейка.Controls.Добавить(Первый);
ячейка.Controls.Add(Предыдущий);
row.Cells.Add(ячейка);
ячейка = новая TableCell();
ячейка.HorizontalAlign= HorizontalAlign.Center;
ячейка.Controls.Add(Пейджер);
row.Cells.Add(ячейка);
ячейка = новая TableCell();
ячейка.VerticalAlign = ВертикальноеВыравнивание.Средний;
ячейка.Controls.Добавить(Далее);
ячейка.Controls.Add(Последний);
row.Cells.Add(ячейка);
control.Controls.Add(таблица);
}
}
DefaultPagerLayout программно предоставляет все элементы навигации и добавляет их на страницу aspx, но на этот раз элементы навигации форматируются с использованием стандартных таблиц HTML. Теперь, если пользователь не предоставляет шаблон презентации, программа автоматически предоставит шаблон по умолчанию.
[TemplateContainer(typeof(LayoutContainer))]
общедоступный макет ITemplate
{
получить {возврат (_layout == null) новый DefaultPagerLayout():_layout;}
установить {_layout = значение;}
}
Давайте посмотрим на процесс генерации номера каждой страницы. Элементу управления подкачкой сначала необходимо определить некоторые значения свойств и использовать эти значения свойств, чтобы определить, сколько разных номеров страниц должно быть сгенерировано.
public int CurrentPage
{
получать
{
строка cur = (строка)ViewState["CurrentPage"];
return (cur == string.Empty || cur ==null) 1: int.Parse(cur);
}
набор
{
ViewState["CurrentPage"] = value.ToString();}
}
public int PagersToShow
{
получить {вернуть _results;}
установить {_results = значение;}
}
public intResultToShow
{
получить {вернуть _resultsperpage;}
set {_resultsperpage = значение;}
}
CurrentPage фактически сохраняет текущую страницу в ViewState номера страницы. Свойства, определенные методом PagersToShow, позволяют пользователю указать, сколько страниц отображать, а свойства, определенныеResultToShow, позволяют пользователю указать, сколько записей нужно отображать. каждая страница. Значение по умолчанию — 10.
NumberofPagersToGenerate возвращает текущее количество номеров страниц, которые должны быть созданы.
частный int PagerSequence
{
получать
{
вернуть Convert.ToInt32
(Math.Ceiling((double)CurrentPage/(double)PagersToShow));}
}
Private int NumberOfPagersToGenerate
{
get{return PagerSequence*PagersToShow;}
}
частный int TotalPagesToShow
{
get{return Convert.ToInt32(Math.Ceiling((double)TotalResults/(double)_resultsperpage));}
}
public int TotalResults
{
получить {вернуть _builder.Adapter.TotalCount;}
}
Метод TotalPagesToShow возвращает общее количество отображаемых страниц, скорректированное заданным пользователем свойствомResultToShow.
Хотя ASP.NET определяет некоторые стили по умолчанию, они могут оказаться не очень практичными для пользователей элементов управления подкачкой. Пользователи могут настроить внешний вид элемента управления страницами с помощью пользовательских стилей.
общедоступный стиль UnSelectedPagerStyle {get {return UnselectedPager;}}
public Style SelectedPagerStyle {get {return SelectedPager;}}
UnSelectedPagerStyle предоставляет стиль, используемый, когда номер страницы не выбран, а SelectedPagerStyle предоставляет стиль, используемый, когда номер страницы выбран.
частная пустота GeneratePagers (элемент управления WebControl)
{
control.Controls.Clear();
int pager = (PagerSequence-1)* PagersToShow +1
для (;pager<=NumberOfPagersToGenerate && pager<=TotalPagesToShow;pager++)
{
ссылка LinkButton = новая LinkButton();
ссылка.Текст = пейджер.ToString();
ссылка.ID = пейджер.ToString();
link.Click += новый EventHandler(this.Pager_Click);
если (link.ID.Equals(CurrentPage.ToString()))
link.MergeStyle(SelectedPagerStyle);
еще
link.MergeStyle(UnSelectedPagerStyle);
control.Controls.Add(ссылка);
control.Controls.Add(new LiteralControl(" "));
}
}
частная пустота GeneratePagers()
{
GeneratePagers (Держатель);
}
Метод GeneratePagers динамически создает все номера страниц, которые являются кнопками типа LinkButton. Атрибуты метки и идентификатора каждого номера страницы назначаются посредством цикла, и в то же время событие щелчка привязывается к соответствующему обработчику событий. Наконец, номер страницы добавляется к элементу управления контейнером — в данном случае к объекту Panel. Идентификатор кнопки служит для определения того, какая кнопка вызвала событие нажатия. Ниже приводится определение обработчика событий:
Private void Pager_Click(отправитель объекта, System.EventArgs e)
{
Кнопка LinkButton = (LinkButton) отправитель;
CurrentPage = int.Parse(button.ID);
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagedEventInvoker.Pager));
Обновлять();
}
Private void Next_Click (отправитель объекта, System.Web.UI.ImageClickEventArgs e)
{
если (CurrentPage<TotalPagesToShow)
Текущая страница++;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagedEventInvoker.Next));
Обновлять();
}
Private voidПредыдущий_Click(отправитель объекта, System.Web.UI.ImageClickEventArgs e)
{
если (Текущая страница > 1)
Текущая страница--;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagedEventInvoker.Previous));
Обновлять();
}
Private void First_Click (отправитель объекта, System.Web.UI.ImageClickEventArgs e)
{
ТекущаяСтраница = 1;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagedEventInvoker.First));
Обновлять();
}
Private void Last_Click (отправитель объекта, System.Web.UI.ImageClickEventArgs e)
{
ТекущаяСтраница = ВсегоPagesToShow;
RaiseEvent(PageChanged, this,new PageChangedEventArgs(CurrentPage,PagedEventInvoker.Last));
Обновлять();
}
Эти обработчики событий похожи тем, что сначала изменяют текущую страницу элемента управления разбиением на страницы, а затем обновляют связанный элемент управления.
частное недействительное обновление()
{
если (!HasParentControlCalledDataBinding) return;
ПрименитьДанныеЧувствительностьПравила();
БиндРодитель();
BoundControl.DataBind();
}
Сначала элемент управления подкачкой проверяет, были ли инициализированы необходимые адаптеры, вызывая метод HasParentControlCalledDataBinding. Если это так, примените ранее указанные правила для автоматической настройки элементов управления на основе условий отображения данных к текущему элементу управления. Эти правила заставляют элемент управления подкачки вести себя по-разному в зависимости от различных условий данных в BoundControl. Хотя эти правила контролируются внутри с помощью элемента управления подкачкой, при необходимости их можно легко вывести из-под контроля с помощью режима состояния [GoF].
public bool IsDataSensitive
{
получить {вернуть _isdatasensitivity;}
set{_isdatasensitivity = значение;}
}
Private bool IsPagerVisible
{
get{return (TotalPagesToShow!= 1) && IsDataSensitive;}
}
Private bool IsPreviousVisible
{
получать
{
вернуть (!IsDataSensitive) верно:
(Текущая страница!= 1);
}
}
Private bool IsNextVisible
{
получать
{
вернуть (!IsDataSensitive) верно:
(ТекущаяСтраница!= TotalPagesToShow);
}
}
частная пустота ApplyDataSensitivityRules()
{
ПерваяКнопка.Видимый = ИсПредыдущийВидимый;
ПредыдущаяКнопка.Видимый = ИсПредыдущийВидимый;
LastButton.Visible = IsNextVisible;
СледующаяКнопка.Видимый = IsNextVisible;
если (IsPagerVisible) GeneratePagers();
}
Метод ApplyDataSensitivityRules реализует предопределенные правила, такие как IsPagerVisible, IsPreviousVisible и IsNextVisible. По умолчанию эти правила включены в элементе управления подкачкой, но пользователь может отключить их, задав свойство IsDataSensitive.
На данный момент часть дисплея элемента управления пейджингом в основном разработана. Последняя оставшаяся завершающая работа — предоставить несколько обработчиков событий, чтобы пользователи могли вносить необходимые изменения при возникновении различных событий управления подкачкой.
публичный делегат void PageDelegate (отправитель объекта, PageChangedEventArgs e);
public enum PagedEventInvoker {Next, Previous, First, Last, Pager}
public class PageChangedEventArgs:EventArgs
{
частная int новая страница;
частный вызов Enum
public PageChangedEventArgs(int newpage):base();
{
this.newpage = новая страница;
}
public PageChangedEventArgs (int newpage, вызов PageChangedEventInvoker)
{
this.newpage = новая страница;
this.invoker = вызывающий;
}
public int NewPage {get{return newpage;}}
public Enum EventInvoker {получить {вернуть вызывающий элемент;}}
}
Поскольку элемент управления подкачкой должен возвращать пользовательские параметры событий, мы определяем специальный класс PageChangedEventArgs. Класс PageChangedEventArgs возвращает тип PagedEventInvoker, который является перечислителем элементов управления, которые могут вызвать событие. Для обработки пользовательских параметров событий мы определяем новый делегат PageDelegate. Событие определяется в следующей форме:
общедоступное событие PageDelegate PageChanged;
открытое событие EventHandler DataUpdate
Если у события нет соответствующего прослушивателя событий, ASP.NET выдаст исключение. Элемент управления подкачкой определяет следующие методы RaiseEvent.
Private void RaiseEvent (EventHandler e, отправитель объекта)
{
this.RaiseEvent(e,this,null);
}
Private void RaiseEvent (EventHandler e, отправитель объекта, аргументы PageChangedEventArgs)
{
если (е! = ноль)
{
е (отправитель, аргументы);
}
}
частный void RaiseEvent (PageDelegate e, отправитель объекта)
{
this.RaiseEvent(e,this,null);
}
Private void RaiseEvent (PageDelegate e, отправитель объекта, аргументы PageChangedEventArgs)
{
если (е! = ноль)
{
е (отправитель, аргументы);
}
}
Обработчики событий теперь могут запускать события, вызывая отдельные методы извлечения.
4. Примеры применения
На этом этапе проектирование управления пейджингом было завершено и может быть официально использовано. Чтобы использовать управление пейджингом, просто свяжите его с управлением презентацией.
<Шаблон предмета>
Столбец 1:
<%# Convert.tostring (databinder.eval (container.dataitem, "column1"))%>
<бр>
Столбец 2:
<%# Convert.tostring (databinder.eval (intainer.dataitem, "column2"))%>
<бр>
Столбец 3:
<%# Convert.tostring (databinder.eval (container.dataitem, "column3"))%>
<бр>
<час>
</ItemTemplate>
</ASP: Repeater >
< CC1: Pager id = "pager" resultStoshow = "2" runat = "server" bindtoControl = "Repeater" >
< SELECEDPAGERSTYLE BACKCOLOR = "Желтый" />
</CC1: Pager >
Приведенная выше страница ASPX связывает элемент управления пейджингом с управлением ретранслятором, устанавливает количество записей, отображаемых на каждой странице, на 2, цвет выбранного номера страницы является желтым и использует макет по умолчанию Как показано на рисунке 1. Ниже приведен еще один пример, который связывает управление пейджингом с помощью данных, как показано на рисунке 2.
< ASP: DataGrid ID = "Grid" Runat = "Server" ></ASP: DataGrid >
< CC1: Pager id = "pagergrid" resultStoshow = "2" runat = "server" bindtoControl = "grid" >
< SELECEDPAGERSTYLE BACKCOLOR = "RED" ></SELECEDPAGERSTYLE >
< Макет >
< ASP: ImageButton id = "First" Runat = "server" ImageUrl = "play2l_dis.gif" alternateText = "Home" ></ASP: ImageButton >
< ASP: ImageButton id = "Предыдущий" Runat = "server" ImageUrl = "play2l.gif" alternateText = "Предыдущая страница" ></asp: imagebutton >
< ASP: ImageButton id = "next" runat = "server" imageUrl = "play2.gif" alternateText = "следующая страница" ></asp: imagebutton >
< ASP: ImageButton id = "last" runat = "server" imageUrl = "play2_dis.gif" alternateText = "Последняя страница" ></ASP: ImageButton >
< ASP: панель идентификатор = "Pager" Runat = "Server" ></ASP: панель >
</макет >
</CC1: Pager >
Тест показывает, что управление пейджин не зависит от конкретных элементов управления презентацией. Полный пример.
Несмотря на то, что обучение для разработки пользовательских веб-контролей является нелегкой задачей, преимущества освоения этого навыка являются самоочевидными с небольшим увеличением рабочей нагрузки, разработчики могут изменить обычные веб-элементы в многоцелевые. Times.
http://www.cnblogs.com/niit007/archive/2006/08/13/475501.html