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


Сортировка данных в элементе управления 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 AllowSorting присвоено значение true, каждое поле GridView со значением 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() Выберите параметр (Нет) в раскрывающихся списках на вкладках ВСТАВКА, ОБНОВЛЕНИЕ и УДАЛЕНИЕ.

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

Рис. 1. Создание objectDataSource и настройка для него использования GetProductsAsPagedDataSource() метода (щелкните для просмотра полноразмерного изображения)

Задайте для Drop-Down Списки на вкладках UPDATE, INSERT и DELETE значение (Нет)

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

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

После добавления ItemTemplateдекларативная разметка Repeater и 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 сортировать данные

Чтобы отсортировать данные, отображаемые в repeater, необходимо сообщить 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 ).

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

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

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

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

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

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

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

Добавление элемента ListItem для каждого поля сортируемых данных

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

Наконец, добавьте элемент управления Button Web справа от 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 свойство s 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 данных, так как оно выбрано SortByListItem по умолчанию (см. рис. 6). Выбор другого параметра сортировки, например Категория и нажатие кнопки Обновить, приведет к обратной отправке и повторной сортировке данных по имени категории, как показано на рисунке 7.

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

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

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

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

Примечание

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

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

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

В этом руководстве 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 класс кода программной части для SortingWithDefaultPaging.aspx. Затем просмотрите страницу SortingWithDefaultPaging.aspx в браузере. Он должен иметь те же функции и внешний вид, что Paging.aspxи .

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

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

Ранее в этом руководстве мы добавили поддержку сортировки, указав выражение сортировки из обработчика Selecting событий ObjectDataSource. Это хорошо работает, когда 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 и присваивает это значение свойству SortProductDataTable объекта s DefaultView. Через несколько строк кода объекту PagedDataSource DataSource назначается ProductDataTable s DefaultView.

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

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

Обновите свойство ObjectDataSource таким SelectMethod образом, чтобы оно вызовет новый GetProductsSortedAsPagedDataSource метод . Затем добавьте новый QueryStringParameter , чтобы доступ к входному параметру sortExpression был получен из поля sortExpressionquerystring . Задайте для QueryStringParameter s 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 поля querystring , если оно существует, и значение по умолчанию ( ProductName ) в противном случае.

В настоящее RedirectUser время метод принимает только один входной параметр индекса отображаемой страницы. Однако в некоторых случаях может потребоваться перенаправить пользователя на определенную страницу данных с помощью выражения сортировки, отличного от указанного в строках запроса. Через некоторое время мы создадим интерфейс сортировки для этой страницы, который будет включать ряд элементов управления Button Web для сортировки данных по указанному столбцу. При нажатии одной из этих кнопок необходимо перенаправить пользователя, передав соответствующее значение выражения сортировки. Чтобы предоставить эту функцию, создайте две версии 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 Web, задав их 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 и не превышающее maximumRows.
  • GetProductsPagedAndSorted(sortExpression, startRowIndex, maximumRows) возвращает определенное подмножество записей, отсортированных по указанному входному параметру sortExpression .
  • TotalNumberOfProducts() предоставляет общее количество записей в Products таблице базы данных.

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

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

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

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

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

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

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

Примечание

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

Наконец, определите значения Repeater 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

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

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, который используется в примере разбиения на страницы по умолчанию, включая элемент управления Label Web, который показывает, какая страница с данными просматривается и сколько всего страниц существует. Добавьте четыре элемента управления Button Web и Label под элементом Repeater.

<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 достаточно прост, но для кнопки Последний как определить индекс начальной строки для последней страницы данных? Чтобы вычислить этот индекс, а также определить, должны ли быть включены кнопки Далее и Последний, необходимо знать, сколько записей в общей сложности выстраиваются. Это можно определить, вызвав 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();
}

Наконец, необходимо отключить кнопки Первый и Предыдущий в интерфейсе подкачки при просмотре первой страницы данных и кнопки Next и Last при просмотре последней страницы. Для этого добавьте следующий код в обработчик событий 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, при первом посещении страницы кнопки Первая и Предыдущая будут отключены. При нажатии кнопки Далее отображается вторая страница данных, а последняя — последняя страница (см. рисунки 16 и 17). При просмотре последней страницы данных отключаются кнопки Далее и Последняя.

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

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

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

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

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

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

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

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

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

Начните с обновления свойства ObjectDataSource SelectMethod и добавления sortExpressionParameter. Убедитесь, что свойству sortExpressionParameter задано Type значение 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;
    }
}

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

e.InputParameters["sortExpression"] = SortExpression;

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

<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 для соответствующего значения и повторно привязите данные к repeater:

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. Отображается последняя страница данных, отсортированная по категориям (щелкните для просмотра полноразмерного изображения)

Примечание

В предыдущих примерах при сортировке по поставщику Имя поставщика использовалось в качестве выражения сортировки. Однако для реализации настраиваемого разбиения по страницам необходимо использовать 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, чтобы предоставить некоторые пользовательские функции для каждого элемента.

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

Об авторе

Скотт Митчелл( Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часах. Он может быть доступен в mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Особая благодарность

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