Поделиться через


Сортировка данных в элементе управления DataList или Repeater (C#)

Скотт Митчелл

Скачать в формате PDF

В этом руководстве мы рассмотрим, как включить поддержку сортировки в DataList и Repeater, а также как создать DataList или Repeater, данные которых можно сортировать и отсортировать.

Введение

В предыдущем руководстве мы рассмотрели, как добавить поддержку разбиения по страницам в DataList. Мы создали новый метод в ProductsBLL классе (GetProductsAsPagedDataSource), который вернул PagedDataSource объект. При привязке к DataList или Repeater объект DataList или Repeater будет отображать только запрошенную страницу данных. Этот метод аналогичен тому, что используется внутренними элементами управления GridView, DetailsView и FormView для предоставления встроенных функций разбиения по умолчанию.

Помимо поддержки разбиения по страницам, GridView также включает в себя поддержку сортировки по полям. Ни DataList, ни Repeater не предоставляют встроенные функции сортировки; Однако функции сортировки можно добавить с помощью немного кода. В этом руководстве мы рассмотрим, как включить поддержку сортировки в DataList и Repeater, а также как создать DataList или Repeater, данные которых можно сортировать и отсортировать.

Проверка сортировки

Как мы видели в руководстве по просмотру и сортировке данных отчета, элемент управления GridView предоставляет поддержку сортировки по полям. Каждое поле GridView может иметь связанное SortExpressionполе, указывающее поле данных для сортировки данных. Если для свойства GridView задано trueзначение, каждое поле GridView AllowSorting со SortExpression значением свойства имеет заголовок, отображаемый как LinkButton. Когда пользователь щелкает определенный заголовок поля GridView, происходит обратная передача данных и данные сортируются в соответствии с полями SortExpression.

Элемент управления GridView также имеет SortExpression свойство, которое сохраняет SortExpression поле GridView, по которому данные сортируются. Кроме того, свойство указывает, SortDirection следует ли отсортировать данные по возрастанию или убыванию (если пользователь дважды щелкает ссылку заголовка поля GridView в последовательности, порядок сортировки переключается).

Когда GridView привязан к элементу управления источниками данных, он передает ему и SortExpression SortDirection свойства в элемент управления источниками данных. Элемент управления источником данных извлекает данные, а затем сортирует его в соответствии с предоставленными SortExpression и SortDirection свойствами. После сортировки данных элемент управления источниками данных возвращает его в GridView.

Чтобы реплицировать эту функцию с помощью элементов управления DataList или Repeater, необходимо:

  • Создание интерфейса сортировки
  • Помните поле данных для сортировки и сортировки по возрастанию или убыванию
  • Указание ObjectDataSource отсортировать данные по определенному полю данных

Мы будем решать эти три задачи в шагах 3 и 4. После этого мы рассмотрим, как включить поддержку разбиения по страницам и сортировки в DataList или Repeater.

Шаг 2. Отображение продуктов в повторе

Прежде чем беспокоиться о реализации любой из функций сортировки, давайте начнем с перечисления продуктов в элементе управления Repeater. Начните с открытия Sorting.aspx страницы в папке PagingSortingDataListRepeater . Добавьте элемент управления Repeater на веб-страницу, задав для свойства значение ID SortableProducts. Из смарт-тега Repeater создайте объект ObjectDataSource с именем ProductsDataSource и настройте его для получения данных из ProductsBLL метода класса GetProducts() . Выберите параметр (Нет) в раскрывающихся списках на вкладках INSERT, UPDATE и DELETE.

Создайте ObjectDataSource и настройте его для использования метода GetProductsAsPagedDataSource()

Рис. 1. Создание объекта ObjectDataSource и настройка метода GetProductsAsPagedDataSource() (щелкните, чтобы просмотреть изображение полного размера)

Установите раскрывающийся список на вкладках UPDATE, INSERT и DELETE (Нет)

Рис. 2. Задайте раскрывающийся список на вкладках UPDATE, INSERT и DELETE (Нет) (Щелкните, чтобы просмотреть изображение полного размера)

В отличие от DataList, Visual Studio не создает ItemTemplate автоматически для элемента управления Repeater после привязки его к источнику данных. Кроме того, мы должны добавить это ItemTemplate декларативно, так как смарт-тег элемента управления Repeater не имеет параметра "Изменить шаблоны" в DataList. Давайте будем использовать то же ItemTemplate самое из предыдущего руководства, которое отображало имя продукта, поставщик и категорию.

После добавления декларативной разметки ItemTemplateRepeater и ObjectDataSource должен выглядеть следующим образом:

<asp:Repeater ID="SortableProducts" DataSourceID="ProductsDataSource"
    EnableViewState="False" runat="server">
    <ItemTemplate>
        <h4><asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Eval("ProductName") %>'></asp:Label></h4>
        Category:
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'></asp:Label><br />
        Supplier:
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'></asp:Label><br />
        <br />
        <br />
    </ItemTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
    SelectMethod="GetProducts">
</asp:ObjectDataSource>

На рисунке 3 показана эта страница при просмотре через браузер.

Отображается имя каждого продукта, поставщик и категория

Рис. 3. Отображается имя каждого продукта, поставщик и категория (щелкните, чтобы просмотреть изображение полного размера)

Шаг 3. Указание ObjectDataSource сортировке данных

Чтобы отсортировать данные, отображаемые в повторитее, необходимо сообщить ObjectDataSource о выражении сортировки, по которому должны быть отсортированы данные. Прежде чем ObjectDataSource извлекает свои данные, он сначала запускает его Selecting событие, которое предоставляет нам возможность указать выражение сортировки. Обработчик Selecting событий передает объект типа ObjectDataSourceSelectingEventArgs, имеющий свойство с именем Arguments типа DataSourceSelectArguments. Класс DataSourceSelectArguments предназначен для передачи запросов, связанных с данными, от потребителя данных к элементу управления источниками данных и содержит SortExpression свойство.

Чтобы передать сведения о сортировке из страницы ASP.NET в ObjectDataSource, создайте обработчик событий для Selecting события и используйте следующий код:

protected void ProductsDataSource_Selecting
    (object sender, ObjectDataSourceSelectingEventArgs e)
{
    e.Arguments.SortExpression = sortExpression;
}

Значение sortExpression должно быть присвоено имени поля данных для сортировки данных по (например, ProductName). Свойство, связанное с направлением сортировки, отсутствует, поэтому если требуется отсортировать данные в порядке убывания, добавьте строку DESC в значение sortExpression (например, ProductName DESC).

Попробуйте использовать различные жестко закодированные значения для сортировкиExpression и протестируйте результаты в браузере. Как показано на рисунке 4, при использовании ProductName DESC в качестве сортировкиExpression продукты сортируются по их имени в обратном алфавитном порядке.

Продукты отсортированы по их имени в алфавитном порядке

Рис. 4. Продукты отсортированы по их имени в алфавитном порядке (щелкните, чтобы просмотреть изображение полного размера)

Шаг 4. Создание интерфейса сортировки и запоминание выражения сортировки и направления

Включение поддержки сортировки в GridView преобразует каждый текст заголовка поля сортировки в LinkButton, который при щелчке сортирует данные соответствующим образом. Такой интерфейс сортировки имеет смысл для GridView, где его данные аккуратно размещаются в столбцах. Однако для элементов управления DataList и Repeater требуется другой интерфейс сортировки. Общий интерфейс сортировки для списка данных (в отличие от сетки данных), представляет собой раскрывающийся список, предоставляющий поля, по которым можно сортировать данные. Давайте реализуем такой интерфейс для этого руководства.

Добавьте веб-элемент управления DropDownList над SortableProducts повторитетелем и задайте для его свойства SortByзначениеID. В окно свойств щелкните многоточие в свойствеItems, чтобы открыть редактор коллекции ListItem. Добавьте ListItem s для сортировки данных по ProductNameCategoryNameполям и SupplierName т. е. Кроме того, добавьте ListItem для сортировки продуктов по их имени в обратном алфавитном порядке.

Свойства ListItem Text можно задать для любого значения (например, name), но Value свойства должны иметь имя поля данных (например, ProductName). Чтобы отсортировать результаты в порядке убывания, добавьте строку DESC в имя поля данных, например ProductName DESC.

Добавление listItem для каждого поля с сортировкой данных

Рис. 5. Добавление ListItem для каждого поля с сортировкой данных

Наконец, добавьте веб-элемент управления Button справа от dropDownList. Присвойте ей ID значение RefreshRepeater и свойству Text Refresh.

После создания ListItem и добавления кнопки "Обновить" декларативный синтаксис DropDownList и Button должны выглядеть следующим образом:

<asp:DropDownList ID="SortBy" runat="server">
    <asp:ListItem Value="ProductName">Name</asp:ListItem>
    <asp:ListItem Value="ProductName DESC">Name (Reverse Order)
        </asp:ListItem>
    <asp:ListItem Value="CategoryName">Category</asp:ListItem>
    <asp:ListItem Value="SupplierName">Supplier</asp:ListItem>
</asp:DropDownList>
<asp:Button runat="server" ID="RefreshRepeater" Text="Refresh" />

После завершения сортировки DropDownList необходимо обновить обработчик событий ObjectDataSource Selecting , чтобы он использовал выбранное SortBy``ListItem свойство в Value отличие от жестко закодированного выражения сортировки.

protected void ProductsDataSource_Selecting
    (object sender, ObjectDataSourceSelectingEventArgs e)
{
    // Have the ObjectDataSource sort the results by the selected
    // sort expression
    e.Arguments.SortExpression = SortBy.SelectedValue;
}

На этом этапе при первом посещении страницы продукты изначально будут отсортированы ProductName по полю данных, так как она SortBy ListItem выбрана по умолчанию (см. рис. 6). Выбор другого параметра сортировки, например "Категория" и нажатие кнопки "Обновить", приведет к обратной отправке и повторной сортировке данных по имени категории, как показано на рисунке 7.

Продукты изначально отсортированы по их имени

Рис. 6. Продукты изначально отсортированы по имени (щелкните, чтобы просмотреть изображение полного размера)

Продукты теперь отсортированы по категориям

Рис. 7. Продукты отсортированы по категориям (щелкните, чтобы просмотреть изображение полного размера)

Примечание.

При нажатии кнопки "Обновить" данные автоматически будут отсортированы, так как состояние представления повторителя было отключено, что приведет к повторной привязке повтора к источнику данных во всех обратных операциях. Если вы оставили состояние представления повтора, изменение раскрывающегося списка не повлияет на порядок сортировки. Чтобы устранить эту проблему, создайте обработчик событий для события "Обновить кнопку Click " и повторно привязите повторите его к источнику данных (вызывая метод Repeater s DataBind() ).

Запоминание выражения сортировки и направления

При создании сортируемого списка данных или повтора на странице, в которой могут возникать не связанные с сортировкой обратные передачи, необходимо помнить выражение сортировки и направление для обратной передачи. Например, представьте, что мы обновили повторитель в этом руководстве, чтобы включить кнопку "Удалить" с каждым продуктом. Когда пользователь нажимает кнопку "Удалить", мы запустите некоторый код, чтобы удалить выбранный продукт, а затем повторно привязали данные к повторитею. Если данные сортировки не сохраняются во время обратной передачи, данные, отображаемые на экране, будут возвращены в исходный порядок сортировки.

В этом руководстве dropDownList неявно сохраняет выражение сортировки и направление в его состоянии представления для нас. Если бы мы использовали другой интерфейс сортировки с, скажем, LinkButtons, которые предоставили различные варианты сортировки, которые мы должны помнить порядок сортировки по обратным точкам. Это можно сделать, сохраняя параметры сортировки в состоянии представления страницы, включив параметр сортировки в строку запроса или через другой метод сохраняемости состояния.

В будущих примерах этого руководства рассматривается сохранение сведений о сортировке в состоянии представления страницы.

Шаг 5. Добавление поддержки сортировки в список данных, использующий разбиение по умолчанию

В предыдущем руководстве мы рассмотрели, как реализовать разбиение по умолчанию с помощью DataList. Давайте расширим этот предыдущий пример, чтобы включить возможность сортировки страничных данных. Начните с открытия SortingWithDefaultPaging.aspx и Paging.aspx страниц в папке PagingSortingDataListRepeater . Paging.aspx На странице нажмите кнопку "Источник", чтобы просмотреть декларативную разметку страницы. Скопируйте выделенный текст (см. рис. 8) и вставьте его в декларативную разметку SortingWithDefaultPaging.aspx между <asp:Content> тегами.

Репликация декларативной разметки в <тегах asp:Content> из Paging.aspx в SortingWithDefaultPaging.aspx

Рис. 8. Репликация декларативной разметки в <asp:Content> тегах из Paging.aspx SortingWithDefaultPaging.aspx (щелкните, чтобы просмотреть изображение полного размера)

После копирования декларативной разметки скопируйте методы и свойства в класс кодовой части страницы в Paging.aspx класс code-behind для SortingWithDefaultPaging.aspx. Затем просмотрите SortingWithDefaultPaging.aspx страницу в браузере. Он должен проявлять те же функциональные возможности и внешний вид, что Paging.aspxи .

Повышение уровня ProductsBLL для включения метода разбиения по умолчанию и сортировки по умолчанию

В предыдущем руководстве мы создали GetProductsAsPagedDataSource(pageIndex, pageSize) метод в ProductsBLL классе, который вернул PagedDataSource объект. Этот PagedDataSource объект был заполнен всеми продуктами (с помощью метода BLL GetProducts() ), но при привязке к DataList отображаются только те записи, соответствующие указанным параметрам pageIndex и pageSize input.

Ранее в этом руководстве мы добавили поддержку сортировки, указав выражение сортировки из обработчика событий ObjectDataSource Selecting . Это хорошо работает, когда объект ObjectDataSource возвращает объект, который можно сортировать, например ProductsDataTable возвращаемый методом GetProducts() . Однако объект, возвращаемый методомGetProductsAsPagedDataSource, PagedDataSource не поддерживает сортировку своего внутреннего источника данных. Вместо этого необходимо отсортировать результаты, возвращаемые из GetProducts() метода, прежде чем поместить его в PagedDataSource.

Для этого создайте новый метод в ProductsBLL классе GetProductsSortedAsPagedDataSource(sortExpression, pageIndex, pageSize). Чтобы отсортировать ProductsDataTable возвращаемый методом GetProducts() , укажите Sort свойство по умолчанию DataTableView:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)]
public PagedDataSource GetProductsSortedAsPagedDataSource
    (string sortExpression, int pageIndex, int pageSize)
{
    // Get ALL of the products
    Northwind.ProductsDataTable products = GetProducts();
    // Sort the products
    products.DefaultView.Sort = sortExpression;
    // Limit the results through a PagedDataSource
    PagedDataSource pagedData = new PagedDataSource();
    pagedData.DataSource = products.DefaultView;
    pagedData.AllowPaging = true;
    pagedData.CurrentPageIndex = pageIndex;
    pagedData.PageSize = pageSize;
    return pagedData;
}

Метод GetProductsSortedAsPagedDataSource отличается лишь немного от метода, созданного GetProductsAsPagedDataSource в предыдущем руководстве. В частности, GetProductsSortedAsPagedDataSource принимает дополнительный входной параметр sortExpression и назначает это значение Sort свойству ProductDataTable s DefaultView. Несколько строк кода позже PagedDataSource присваивается ProductDataTable DefaultViewобъекту DataSource.

Вызов метода GetProductsSortedAsPagedDataSource и указание значения для входного параметра SortExpression

GetProductsSortedAsPagedDataSource После завершения метода необходимо указать значение этого параметра. Объект ObjectDataSource в SortingWithDefaultPaging.aspx настоящее время настроен для вызова GetProductsAsPagedDataSource метода и передает два входных параметра через два QueryStringParametersвходных параметра, указанных в SelectParameters коллекции. Эти два QueryStringParameters указывают, что источник для GetProductsAsPagedDataSource параметров pageIndex метода и pageSize приходят из полей pageIndex запроса и pageSize.

Обновите свойство ObjectDataSource SelectMethod , чтобы вызвать новый GetProductsSortedAsPagedDataSource метод. Затем добавьте новый QueryStringParameter , чтобы входной параметр sortExpression был получен из поля sortExpressionзапроса. Задайте для s QueryStringParameter DefaultValue значение ProductName.

После этих изменений декларативная разметка ObjectDataSource должна выглядеть следующим образом:

<asp:ObjectDataSource ID="ProductsDefaultPagingDataSource"
    OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
    SelectMethod="GetProductsSortedAsPagedDataSource"
    OnSelected="ProductsDefaultPagingDataSource_Selected" runat="server">
    <SelectParameters>
        <asp:QueryStringParameter DefaultValue="ProductName"
            Name="sortExpression" QueryStringField="sortExpression"
            Type="String" />
        <asp:QueryStringParameter DefaultValue="0" Name="pageIndex"
            QueryStringField="pageIndex" Type="Int32" />
        <asp:QueryStringParameter DefaultValue="4" Name="pageSize"
            QueryStringField="pageSize" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

На этом этапе SortingWithDefaultPaging.aspx страница отсортирует результаты в алфавитном порядке по имени продукта (см. рис. 9). Это связано с тем, что по умолчанию значение ProductName передается в качестве GetProductsSortedAsPagedDataSource параметра sortExpression метода.

По умолчанию результаты отсортированы по ProductName

Рис. 9. По умолчанию результаты отсортированы ProductName по (щелкните, чтобы просмотреть изображение полного размера)

Если добавить поле строки запросов вручную sortExpression , например SortingWithDefaultPaging.aspx?sortExpression=CategoryName результаты, будут отсортированы указанным sortExpression. Однако этот sortExpression параметр не включается в строку запросов при переходе на другую страницу данных. На самом деле нажатие кнопки "Далее" или "Последняя страница" возвращает нас к Paging.aspx! Кроме того, в настоящее время нет интерфейса сортировки. Единственный способ, которым пользователь может изменить порядок сортировки страничных данных, заключается в непосредственном управлении строками запросов.

Создание интерфейса сортировки

Сначала необходимо обновить RedirectUser метод, чтобы отправить пользователю SortingWithDefaultPaging.aspx (а не Paging.aspx) значение sortExpression в строку запроса. Мы также должны добавить именованное свойство уровня SortExpression страницы только для чтения. Это свойство, аналогичное PageIndex PageSize свойствам, созданным в предыдущем руководстве, возвращает значение поля запроса, если оно существует, и значение sortExpression по умолчанию (ProductName) в противном случае.

RedirectUser В настоящее время метод принимает только один входной параметр, индекс страницы для отображения. Однако может возникнуть время, когда нужно перенаправить пользователя на определенную страницу данных, используя выражение сортировки, отличное от того, что указано в запросе. На данный момент мы создадим интерфейс сортировки для этой страницы, который будет включать ряд веб-элементов управления Button для сортировки данных по указанному столбцу. Щелкнув одну из этих кнопок, мы хотим перенаправить пользователя, передавающего соответствующее значение выражения сортировки. Чтобы обеспечить эту функциональность, создайте две версии RedirectUser метода. Первый должен принять только индекс страницы для отображения, а второй принимает индекс страницы и выражение сортировки.

private string SortExpression
{
    get
    {
        if (!string.IsNullOrEmpty(Request.QueryString["sortExpression"]))
            return Request.QueryString["sortExpression"];
        else
            return "ProductName";
    }
}
private void RedirectUser(int sendUserToPageIndex)
{
    // Use the SortExpression property to get the sort expression
    // from the querystring
    RedirectUser(sendUserToPageIndex, SortExpression);
}
private void RedirectUser(int sendUserToPageIndex, string sendUserSortingBy)
{
   // Send the user to the requested page with the requested sort expression
   Response.Redirect(string.Format(
      "SortingWithDefaultPaging.aspx?pageIndex={0}&pageSize={1}&sortExpression={2}",
      sendUserToPageIndex, PageSize, sendUserSortingBy));
}

В первом примере этого руководства мы создали интерфейс сортировки с помощью DropDownList. В этом примере мы будем использовать три элемента управления Button Web, расположенные над элементом DataList, для сортировки ProductNameпо одному для CategoryName, а также один для SupplierName. Добавьте три веб-элемента управления Button, задав их ID и Text свойства соответствующим образом:

<p>
    <asp:Button runat="server" id="SortByProductName"
        Text="Sort by Product Name" />
    <asp:Button runat="server" id="SortByCategoryName"
        Text="Sort by Category" />
    <asp:Button runat="server" id="SortBySupplierName"
        Text="Sort by Supplier" />
</p>

Затем создайте Click обработчик событий для каждого. Обработчики событий должны вызывать RedirectUser метод, возвращая пользователя на первую страницу с помощью соответствующего выражения сортировки.

protected void SortByProductName_Click(object sender, EventArgs e)
{
    // Sort by ProductName
    RedirectUser(0, "ProductName");
}
protected void SortByCategoryName_Click(object sender, EventArgs e)
{
    // Sort by CategoryName
    RedirectUser(0, "CategoryName");
}
protected void SortBySupplierName_Click(object sender, EventArgs e)
{
    // Sort by SupplierName
    RedirectUser(0, "SupplierName");
}

При первом посещении страницы данные сортируются по имени продукта в алфавитном порядке (вернитесь на рис. 9). Нажмите кнопку "Далее", чтобы перейти на вторую страницу данных, а затем нажмите кнопку "Сортировка по категориям". Это возвращает нас на первую страницу данных, отсортированную по имени категории (см. рис. 10). Аналогичным образом нажатие кнопки "Сортировка по поставщику" сортирует данные по поставщику, начиная с первой страницы данных. Выбор сортировки запоминается при просмотре данных. На рисунке 11 показана страница после сортировки по категориям, а затем перейдите на тринадцатую страницу данных.

Продукты отсортированы по категориям

Рис. 10. Продукты отсортированы по категориям (щелкните, чтобы просмотреть изображение полного размера)

Выражение сортировки запоминается при разбиении по страницам с помощью данных

Рис. 11. Выражение сортировки запоминается при разбиении по страницам (щелкните, чтобы просмотреть изображение полного размера)

Шаг 6. Настраиваемое разбиение по страницам в повторе

Пример DataList, рассмотренный на шаге 5 страниц, с помощью неэффективного метода разбиения по умолчанию. При разбиении по страницам достаточно больших объемов данных крайне важно использовать настраиваемое разбиение по страницам. Еще в учебниках по эффективному разбиению на страницы с помощью больших объемов данных и сортировке пользовательских страничных данных мы рассмотрели различия между пользовательскими по умолчанию и пользовательскими разбиениями по страницам и созданными методами в BLL для использования пользовательских разбиений на страницы и сортировки пользовательских данных страниц. В частности, в этих двух предыдущих руководствах мы добавили в класс следующие три метода ProductsBLL :

  • GetProductsPaged(startRowIndex, maximumRows) возвращает определенное подмножество записей, начиная с startRowIndex и не превышающее максимальные значенияRows.
  • GetProductsPagedAndSorted(sortExpression, startRowIndex, maximumRows) возвращает определенное подмножество записей, отсортированных по указанному входному параметру sortExpression .
  • TotalNumberOfProducts() предоставляет общее количество записей в Products таблице базы данных.

Эти методы можно использовать для эффективной страницы и сортировки данных с помощью элемента управления DataList или Repeater. Чтобы проиллюстрировать это, давайте начнем с создания элемента управления Repeater с поддержкой пользовательского разбиения по страницам; Затем мы добавим возможности сортировки.

SortingWithCustomPaging.aspx Откройте страницу в PagingSortingDataListRepeater папке и добавьте повторитель на страницу, задав для свойства значение ID Products. В смарт-теге Повторителя создайте новый объект ObjectDataSource с именем ProductsDataSource. Настройте его для выбора данных из ProductsBLL метода класса GetProductsPaged .

Настройка ObjectDataSource для использования метода GetProductsPaged класса ProductsBLL

Рис. 12. Настройка ObjectDataSource для использования ProductsBLL метода класса GetProductsPaged (щелкните, чтобы просмотреть изображение полного размера)

Установите раскрывающийся список на вкладках UPDATE, INSERT и DELETE (Нет) и нажмите кнопку "Далее". Мастер настройки источника данных теперь запрашивает источники входных GetProductsPaged параметров метода startRowIndex и maximumRows . В действительности эти входные параметры игнорируются. Вместо этого значения startRowIndex и maximumRows передаются через Arguments свойство в обработчике событий ObjectDataSource Selecting , как и в том, как мы указали sortExpression в этом руководстве в первой демонстрации. Поэтому оставьте раскрывающийся список источников параметров в мастере, заданном в none.

Оставьте для источников параметров значение None

Рис. 13. Оставьте для источников параметров значение "Нет" (щелкните, чтобы просмотреть изображение полного размера)

Примечание.

Не устанавливайте для свойства ObjectDataSource EnablePaging значение true. Это приведет к автоматическому включению собственных параметров startRowIndex и maximumRows в существующий SelectMethod список параметров. Это EnablePaging свойство полезно при привязке пользовательских страничных данных к элементу управления GridView, DetailsView или FormView, так как эти элементы управления ожидают определенного поведения от ObjectDataSource, доступного только при EnablePaging наличии trueсвойства. Так как мы должны вручную добавить поддержку разбиения на страницы для DataList и Repeater, оставьте это свойство равным false (по умолчанию), так как мы будем создавать необходимые функции непосредственно на странице ASP.NET.

Наконец, определите повторяющийся элемент ItemTemplate , чтобы отображалось имя продукта, категория и поставщик. После этих изменений декларативный синтаксис Repeater и ObjectDataSource должен выглядеть следующим образом:

<asp:Repeater ID="Products" runat="server" DataSourceID="ProductsDataSource"
    EnableViewState="False">
    <ItemTemplate>
        <h4><asp:Label ID="ProductNameLabel" runat="server"
            Text='<%# Eval("ProductName") %>'></asp:Label></h4>
        Category:
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'></asp:Label><br />
        Supplier:
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'></asp:Label><br />
        <br />
        <br />
    </ItemTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductsPaged" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:Parameter Name="startRowIndex" Type="Int32" />
        <asp:Parameter Name="maximumRows" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Перейдите на страницу через браузер и обратите внимание, что записи не возвращаются. Это связано с тем, что мы еще не указали значения параметров startRowIndex и maximumRows , поэтому значения 0 передаются для обоих. Чтобы указать эти значения, создайте обработчик событий для события ObjectDataSource Selecting и установите эти значения параметров программным образом для жестко закодированных значений 0 и 5 соответственно:

protected void ProductsDataSource_Selecting
    (object sender, ObjectDataSourceSelectingEventArgs e)
{
    e.InputParameters["startRowIndex"] = 0;
    e.InputParameters["maximumRows"] = 5;
}

При этом изменении страница при просмотре через браузер отображает первые пять продуктов.

Отображаются первые пять записей

Рис. 14. Отображаются первые пять записей (щелкните, чтобы просмотреть изображение полного размера)

Примечание.

Продукты, перечисленные на рис. 14, будут отсортированы по имени продукта, так как GetProductsPaged хранимая процедура, которая выполняет эффективный настраиваемый запрос на разбиение по запросам ProductName.

Чтобы разрешить пользователю переходить по страницам, необходимо отслеживать начальный индекс строки и максимальные строки и запоминать эти значения во время обратной передачи. В примере разбиения по умолчанию мы использовали поля запроса для сохранения этих значений; для этой демонстрации давайте сохраняем эти сведения в состоянии представления страницы. Создайте следующие два свойства:

private int StartRowIndex
{
    get
    {
        object o = ViewState["StartRowIndex"];
        if (o == null)
            return 0;
        else
            return (int)o;
    }
    set
    {
        ViewState["StartRowIndex"] = value;
    }
}
private int MaximumRows
{
    get
    {
        object o = ViewState["MaximumRows"];
        if (o == null)
            return 5;
        else
            return (int)o;
    }
    set
    {
        ViewState["MaximumRows"] = value;
    }
}

Затем обновите код в обработчике событий Selecting, чтобы он использовал StartRowIndex и MaximumRows свойства вместо жестко закодированных значений 0 и 5:

e.InputParameters["startRowIndex"] = StartRowIndex;
e.InputParameters["maximumRows"] = MaximumRows;

На этом этапе наша страница по-прежнему отображает только первые пять записей. Однако с этими свойствами мы готовы создать наш интерфейс разбиения на страницы.

Добавление интерфейса разбиения по страницам

Давайте будем использовать тот же интерфейс first, Previous, Next, Last paging, используемый в примере разбиения на страницы по умолчанию, включая веб-элемент управления Label, который отображает страницу данных и сколько страниц существует. Добавьте четыре веб-элемента управления Button и Label под повторитетелем.

<p>
    <asp:Button runat="server" ID="FirstPage" Text="<< First" />
    <asp:Button runat="server" ID="PrevPage" Text="< Prev" />
    <asp:Button runat="server" ID="NextPage" Text="Next >" />
    <asp:Button runat="server" ID="LastPage" Text="Last >>" />
</p>
<p>
    <asp:Label runat="server" ID="CurrentPageNumber"></asp:Label>
</p>

Затем создайте Click обработчики событий для четырех кнопок. При щелчке одной из этих кнопок необходимо обновить и повторно привязать StartRowIndex данные к повторителям. Код для кнопок First, Previous и Next достаточно прост, но для последней кнопки как определить начальный индекс строки для последней страницы данных? Чтобы вычислить этот индекс, а также определить, следует ли включить кнопки Next и Last, необходимо знать, сколько записей в общей сложности страницы выполняется. Это можно определить, вызвав ProductsBLL метод класса TotalNumberOfProducts() . Давайте создадим свойство уровня страницы, доступное TotalRowCount только для чтения, которое возвращает результаты TotalNumberOfProducts() метода:

private int TotalRowCount
{
    get
    {
        // Return the value from the TotalNumberOfProducts() method
        ProductsBLL productsAPI = new ProductsBLL();
        return productsAPI.TotalNumberOfProducts();
    }
}

С помощью этого свойства теперь можно определить индекс начальной строки последней страницы. В частности, это целый результат TotalRowCount минус 1, разделенный MaximumRowsна , умноженный на MaximumRows. Теперь можно написать Click обработчики событий для четырех кнопок интерфейса разбиения по страницам:

protected void FirstPage_Click(object sender, EventArgs e)
{
    // Return to StartRowIndex of 0 and rebind data
    StartRowIndex = 0;
    Products.DataBind();
}
protected void PrevPage_Click(object sender, EventArgs e)
{
    // Subtract MaximumRows from StartRowIndex and rebind data
    StartRowIndex -= MaximumRows;
    Products.DataBind();
}
protected void NextPage_Click(object sender, EventArgs e)
{
    // Add MaximumRows to StartRowIndex and rebind data
    StartRowIndex += MaximumRows;
    Products.DataBind();
}
protected void LastPage_Click(object sender, EventArgs e)
{
    // Set StartRowIndex = to last page's starting row index and rebind data
    StartRowIndex = ((TotalRowCount - 1) / MaximumRows) * MaximumRows;
    Products.DataBind();
}

Наконец, при просмотре первой и последней страницы при просмотре первой и последней кнопок необходимо отключить кнопки First и Previous в интерфейсе разбиения на страницы. Для этого добавьте следующий код в обработчик событий ObjectDataSource Selecting :

// Disable the paging interface buttons, if needed
FirstPage.Enabled = StartRowIndex != 0;
PrevPage.Enabled = StartRowIndex != 0;
int LastPageStartRowIndex = ((TotalRowCount - 1) / MaximumRows) * MaximumRows;
NextPage.Enabled = StartRowIndex < LastPageStartRowIndex;
LastPage.Enabled = StartRowIndex < LastPageStartRowIndex;

После добавления этих Click обработчиков событий и кода для включения или отключения элементов интерфейса разбиения на страницы на основе текущего индекса начальной строки проверьте страницу в браузере. Как показано на рисунке 15, при первом посещении страницы будут отключены кнопки First и Previous. При нажатии кнопки "Далее" отображается вторая страница данных, при нажатии кнопки "Последний" отображается окончательная страница (см. цифры 16 и 17). При просмотре последней страницы данных отключаются кнопки "Далее" и "Последний".

Предыдущие и последние кнопки отключены при просмотре первой страницы продуктов

Рис. 15. Предыдущие и последние кнопки отключены при просмотре первой страницы продуктов (щелкните, чтобы просмотреть изображение полного размера)

Отображается вторая страница продуктов

Рис. 16. Отображается вторая страница продуктов (щелкните, чтобы просмотреть изображение полного размера)

Нажатие кнопки

Рис. 17. Щелкнув последнюю страницу данных (щелкните, чтобы просмотреть изображение полного размера)

Шаг 7. Включение поддержки сортировки с пользовательским повторителем страниц

Теперь, когда настраиваемое разбиение на страницах реализовано, мы готовы включить поддержку сортировки. Метод ProductsBLL класса GetProductsPagedAndSorted имеет одинаковые входные параметры startRowIndex и maximumRows , но GetProductsPagedразрешает дополнительный входной параметр sortExpression . Чтобы использовать GetProductsPagedAndSorted метод из SortingWithCustomPaging.aspx, необходимо выполнить следующие действия:

  1. Измените свойство ObjectDataSource SelectMethod на GetProductsPaged GetProductsPagedAndSorted.
  2. Добавьте объект sortExpression Parameter в коллекцию ObjectDataSourceSelectParameters.
  3. Создайте частное свойство уровня SortExpression страницы, которое сохраняет его значение в обратной связи через состояние представления страницы.
  4. Обновите обработчик событий ObjectDataSource, чтобы назначить параметр sortExpression ObjectDataSource Selecting значение свойства уровня SortExpression страницы.
  5. Создайте интерфейс сортировки.

Сначала обновите свойство ObjectDataSource SelectMethod и добавьте sortExpressionParameter. Убедитесь, что для свойства sortExpression Type Parameter задано значение .String После выполнения этих первых двух задач декларативная разметка ObjectDataSource должна выглядеть следующим образом:

<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}" TypeName="ProductsBLL"
    SelectMethod="GetProductsPagedAndSorted"
    OnSelecting="ProductsDataSource_Selecting">
    <SelectParameters>
        <asp:Parameter Name="sortExpression" Type="String" />
        <asp:Parameter Name="startRowIndex" Type="Int32" />
        <asp:Parameter Name="maximumRows" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Далее нам нужно свойство уровня SortExpression страницы, значение которого сериализуется для просмотра состояния. Если значение выражения сортировки не задано, используйте ProductName в качестве значения по умолчанию:

private string SortExpression
{
    get
    {
        object o = ViewState["SortExpression"];
        if (o == null)
            return "ProductName";
        else
            return o.ToString();
    }
    set
    {
        ViewState["SortExpression"] = value;
    }
}

Прежде чем ObjectDataSource вызывает GetProductsPagedAndSorted метод, необходимо задать sortExpression Parameter значение SortExpression свойства. Selecting В обработчике событий добавьте следующую строку кода:

e.InputParameters["sortExpression"] = SortExpression;

Все, что остается, заключается в реализации интерфейса сортировки. Как мы сделали в последнем примере, давайте реализуем интерфейс сортировки с помощью трех элементов управления Button Web, которые позволяют пользователю сортировать результаты по имени продукта, категории или поставщику.

<asp:Button runat="server" id="SortByProductName"
    Text="Sort by Product Name" />
<asp:Button runat="server" id="SortByCategoryName"
    Text="Sort by Category" />
<asp:Button runat="server" id="SortBySupplierName"
    Text="Sort by Supplier" />

Создайте Click обработчики событий для этих трех элементов управления Button. В обработчике событий сбросьте StartRowIndex значение 0, задайте SortExpression соответствующее значение и повторно привязите данные к повторители:

protected void SortByProductName_Click(object sender, EventArgs e)
{
    StartRowIndex = 0;
    SortExpression = "ProductName";
    Products.DataBind();
}
protected void SortByCategoryName_Click(object sender, EventArgs e)
{
    StartRowIndex = 0;
    SortExpression = "CategoryName";
    Products.DataBind();
}
protected void SortBySupplierName_Click(object sender, EventArgs e)
{
    StartRowIndex = 0;
    SortExpression = "CompanyName";
    Products.DataBind();
}

Это все, что есть к нему! Хотя было несколько шагов для получения пользовательского разбиения по страницам и сортировки, шаги были очень похожи на те, которые необходимы для разбиения по умолчанию. На рисунке 18 показаны продукты при просмотре последней страницы данных при сортировке по категориям.

Отображается последняя страница данных, отсортированная по категориям

Рис. 18. Последняя страница данных, отсортированная по категориям, отображается (щелкните, чтобы просмотреть изображение полного размера)

Примечание.

В предыдущих примерах при сортировке по поставщику SupplierName использовалось в качестве выражения сортировки. Однако для пользовательской реализации разбиения на страницах необходимо использовать CompanyName. Это связано с тем, что хранимая процедура, отвечающая за реализацию пользовательского разбиения GetProductsPagedAndSorted по страницам, передает выражение сортировки в ROW_NUMBER() ключевое слово, ROW_NUMBER() ключевое слово требует фактического имени столбца, а не псевдонима. Поэтому мы должны использовать CompanyName (имя столбца в Suppliers таблице), а не псевдоним, используемый в SELECT запросе (SupplierName) для выражения сортировки.

Итоги

Не поддерживается встроенная поддержка сортировки DataList или Repeater, но с небольшим кодом и пользовательским интерфейсом сортировки, такие функциональные возможности можно добавить. При реализации сортировки, но не разбиения по страницам выражение сортировки можно указать с помощью объекта, переданного DataSourceSelectArguments в метод ObjectDataSource Select . Это DataSourceSelectArguments свойство объекта SortExpression можно назначить в обработчике событий ObjectDataSource Selecting .

Чтобы добавить возможности сортировки в DataList или Repeater, которые уже поддерживают разбиение по страницам, проще всего настроить уровень бизнес-логики для включения метода, который принимает выражение сортировки. Затем эти сведения можно передать через параметр в объекте ObjectDataSource SelectParameters.

В этом руководстве мы завершаем изучение разбиения по страницам и сортировки с помощью элементов управления DataList и Repeater. В следующем и последнем руководстве показано, как добавить веб-элементы управления button в шаблоны DataList и Repeater, чтобы предоставить некоторые пользовательские функции, инициированные пользователем, на основе каждого элемента.

Счастливое программирование!

Об авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Сэмс Учит себя ASP.NET 2.0 в 24 часах. Он может быть достигнут в mitchell@4GuysFromRolla.com. или через его блог, который можно найти на http://ScottOnWriting.NET.

Особое спасибо

Эта серия учебников была проверена многими полезными рецензентами. Ведущий рецензент для этого руководства был Дэвид Суру. Хотите просмотреть мои предстоящие статьи MSDN? Если да, упадите меня линию в mitchell@4GuysFromRolla.com.