Classificação de dados em um controle DataList ou Repeater (C#)

por Scott Mitchell

Baixar PDF

Neste tutorial, examinaremos como incluir o suporte de classificação no DataList e repeater, bem como como construir um DataList ou Repeater cujos dados podem ser paginados e classificados.

Introdução

No tutorial anterior , examinamos como adicionar suporte à paginação a um DataList. Criamos um novo método na ProductsBLL classe (GetProductsAsPagedDataSource) que retornou um PagedDataSource objeto . Quando associado a um DataList ou Repeater, o DataList ou Repeater exibiria apenas a página de dados solicitada. Essa técnica é semelhante ao que é usado internamente pelos controles GridView, DetailsView e FormView para fornecer sua funcionalidade de paginação padrão interna.

Além de oferecer suporte à paginação, o GridView também inclui suporte de classificação pronto para uso. Nem o DataList nem o Repeater fornecem funcionalidade de classificação interna; no entanto, os recursos de classificação podem ser adicionados com um pouco de código. Neste tutorial, examinaremos como incluir o suporte de classificação no DataList e repeater, bem como como construir um DataList ou Repeater cujos dados podem ser paginados e classificados.

Uma revisão de classificação

Como vimos no tutorial Paginação e Classificação de Dados do Relatório , o controle GridView fornece suporte de classificação pronto para uso. Cada campo GridView pode ter um associado SortExpression, que indica o campo de dados pelo qual classificar os dados. Quando a propriedade gridView é AllowSorting definida truecomo , cada campo GridView que tem um SortExpression valor de propriedade tem seu cabeçalho renderizado como um LinkButton. Quando um usuário clica em um determinado cabeçalho do campo GridView, ocorre um postback e os dados são classificados de acordo com o campo clicado s SortExpression.

O controle GridView também tem uma SortExpression propriedade , que armazena o SortExpression do campo GridView pelo qual os dados são classificados. Além disso, uma SortDirection propriedade indica se os dados devem ser classificados em ordem crescente ou decrescente (se um usuário clicar em um link de cabeçalho do campo GridView específico duas vezes seguidas, a ordem de classificação será alternada).

Quando o GridView está associado ao controle da fonte de dados, ele entrega suas SortExpression propriedades e SortDirection ao controle da fonte de dados. O controle da fonte de dados recupera os dados e os classifica de acordo com as propriedades fornecidas SortExpression e SortDirection . Depois de classificar os dados, o controle da fonte de dados os retorna para o GridView.

Para replicar essa funcionalidade com os controles DataList ou Repeater, devemos:

  • Criar uma interface de classificação
  • Lembre-se do campo de dados pelo qual classificar e se deseja classificar em ordem crescente ou decrescente
  • Instruir o ObjectDataSource a classificar os dados por um campo de dados específico

Abordaremos essas três tarefas nas etapas 3 e 4. Depois disso, examinaremos como incluir suporte de paginação e classificação em um DataList ou Repeater.

Etapa 2: Exibindo os produtos em um repetidor

Antes de nos preocuparmos em implementar qualquer uma das funcionalidades relacionadas à classificação, vamos começar listando os produtos em um controle Repeater. Comece abrindo a Sorting.aspx página na PagingSortingDataListRepeater pasta . Adicione um controle Repeater à página da Web, definindo sua ID propriedade SortableProductscomo . Na marca inteligente Repeater s, crie um novo ObjectDataSource chamado ProductsDataSource e configure-o para recuperar dados do ProductsBLL método da classe s GetProducts() . Selecione a opção (Nenhum) nas listas suspensas nas guias INSERT, UPDATE e DELETE.

Criar um ObjectDataSource e configurá-lo para usar o método GetProductsAsPagedDataSource()

Figura 1: Criar um ObjectDataSource e configurá-lo para usar o GetProductsAsPagedDataSource() método (clique para exibir a imagem em tamanho real)

Defina o Drop-Down Listas nas guias UPDATE, INSERT e DELETE como (Nenhum)

Figura 2: Definir o Drop-Down Listas nas guias UPDATE, INSERT e DELETE como (Nenhum) (Clique para exibir a imagem em tamanho real)

Ao contrário do DataList, o Visual Studio não cria automaticamente um ItemTemplate para o controle Repeater depois de vinculá-lo a uma fonte de dados. Além disso, devemos adicioná-lo ItemTemplate declarativamente, pois a marca inteligente do controle Repeater não tem a opção Editar Modelos encontrada na lista de dados. Vamos usar o mesmo ItemTemplate do tutorial anterior, que exibiu o nome, o fornecedor e a categoria do produto.

Depois de adicionar o ItemTemplate, a marcação declarativa de Repeater e ObjectDataSource deve ser semelhante à seguinte:

<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>

A Figura 3 mostra essa página quando exibida por meio de um navegador.

Cada Nome, Fornecedor e Categoria de Cada Produto é Exibido

Figura 3: Cada Nome, Fornecedor e Categoria de Cada Produto é Exibido (Clique para exibir a imagem em tamanho real)

Etapa 3: Instruindo o ObjectDataSource a classificar os dados

Para classificar os dados exibidos no Repeater, precisamos informar o ObjectDataSource da expressão de classificação pela qual os dados devem ser classificados. Antes que o ObjectDataSource recupere seus dados, ele primeiro dispara seu Selecting evento, o que fornece uma oportunidade para especificarmos uma expressão de classificação. O Selecting manipulador de eventos é passado um objeto do tipo ObjectDataSourceSelectingEventArgs, que tem uma propriedade chamada Arguments do tipo DataSourceSelectArguments. A DataSourceSelectArguments classe foi projetada para passar solicitações relacionadas a dados de um consumidor de dados para o controle da fonte de dados e inclui uma SortExpression propriedade .

Para passar informações de classificação da página ASP.NET para o ObjectDataSource, crie um manipulador de eventos para o Selecting evento e use o seguinte código:

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

O valor sortExpression deve receber o nome do campo de dados para classificar os dados por (como ProductName ). Não há nenhuma propriedade relacionada à direção de classificação, portanto, se você quiser classificar os dados em ordem decrescente, acrescente a cadeia de caracteres DESC ao valor sortExpression (como ProductName DESC ).

Vá em frente e tente alguns valores embutidos em código diferentes para sortExpression e teste os resultados em um navegador. Como mostra a Figura 4, ao usar ProductName DESC como sortExpression, os produtos são classificados por seu nome em ordem alfabética inversa.

Os produtos são classificados por seu nome em ordem alfabética inversa

Figura 4: Os produtos são classificados por seu nome em ordem alfabética inversa (clique para exibir a imagem em tamanho real)

Etapa 4: Criando a interface de classificação e lembrando a expressão de classificação e a direção

Ativar o suporte à classificação no GridView converte cada texto de cabeçalho de campo classificável em um LinkButton que, quando clicado, classifica os dados de acordo. Essa interface de classificação faz sentido para o GridView, em que seus dados são dispostos perfeitamente em colunas. No entanto, para os controles DataList e Repeater, é necessária uma interface de classificação diferente. Uma interface de classificação comum para uma lista de dados (em vez de uma grade de dados), é uma lista suspensa que fornece os campos pelos quais os dados podem ser classificados. Vamos implementar essa interface para este tutorial.

Adicione um controle Web DropDownList acima do SortableProducts Repeater e defina sua ID propriedade como SortBy. No janela Propriedades, clique nas reticências na Items propriedade para abrir a Editor Coleção ListItem. Adicione ListItem s para classificar os dados pelos ProductNamecampos , CategoryNamee SupplierName . Adicione também um ListItem para classificar os produtos pelo nome em ordem alfabética inversa.

As ListItemText propriedades podem ser definidas como qualquer valor (como Nome ), mas as Value propriedades devem ser definidas como o nome do campo de dados (como ProductName ). Para classificar os resultados em ordem decrescente, acrescente a cadeia de caracteres DESC ao nome do campo de dados, como ProductName DESC .

Adicionar um ListItem para cada um dos campos de dados classificáveis

Figura 5: Adicionar um para cada um ListItem dos campos de dados classificáveis

Por fim, adicione um controle Web button à direita do DropDownList. Defina como IDRefreshRepeater e sua Text propriedade como Atualizar .

Depois de criar o ListItem s e adicionar o botão Atualizar, a sintaxe declarativa de DropDownList e Button deve ser semelhante à seguinte:

<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" />

Com a classificação dropDownList concluída, precisamos atualizar o manipulador de eventos objectDataSource para Selecting que ele use a propriedade s Value selecionada SortBy``ListItem em vez de uma expressão de classificação embutida em código.

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

Neste ponto, ao visitar a página pela primeira vez, os produtos serão inicialmente classificados pelo ProductName campo de dados, pois ele é o SortByListItem selecionado por padrão (consulte a Figura 6). Selecionar uma opção de classificação diferente, como Categoria e clicar em Atualizar, causará um postback e classificará novamente os dados pelo nome da categoria, como mostra a Figura 7.

Os produtos são inicialmente classificados por seu nome

Figura 6: Os produtos são inicialmente classificados pelo nome (clique para exibir a imagem em tamanho real)

Os produtos agora são classificados por categoria

Figura 7: Os produtos agora são classificados por categoria (clique para exibir a imagem em tamanho real)

Observação

Clicar no botão Atualizar faz com que os dados sejam automaticamente classificados novamente porque o estado de exibição do Repetidor foi desabilitado, fazendo com que o Repetidor seja reassociado à fonte de dados em cada postback. Se você deixou o estado de exibição do Repetidor habilitado, alterar a lista suspensa de classificação não terá nenhum efeito na ordem de classificação. Para corrigir isso, crie um manipulador de eventos para o evento do Click Botão Atualizar e reassociar o Repetidor à fonte de dados (chamando o método Repeater s DataBind() ).

Lembrando a expressão de classificação e a direção

Ao criar um DataList ou Repeater classificável em uma página em que postbacks não relacionados à classificação podem ocorrer, é imperativo que a expressão de classificação e a direção sejam lembradas entre postbacks. Por exemplo, imagine que atualizamos o Repetidor neste tutorial para incluir um botão Excluir com cada produto. Quando o usuário clica no botão Excluir, executamos algum código para excluir o produto selecionado e, em seguida, reassociamos os dados ao Repetidor. Se os detalhes de classificação não forem persistidos no postback, os dados exibidos na tela reverter à ordem de classificação original.

Para este tutorial, o DropDownList salva implicitamente a expressão de classificação e a direção em seu estado de exibição para nós. Se estivéssemos usando uma interface de classificação diferente com, digamos, LinkButtons que forneceu as várias opções de classificação, precisaríamos ter cuidado para lembrar a ordem de classificação entre postbacks. Isso pode ser feito armazenando os parâmetros de classificação no estado de exibição da página, incluindo o parâmetro de classificação na querystring ou por meio de alguma outra técnica de persistência de estado.

Exemplos futuros neste tutorial exploram como persistir os detalhes de classificação no estado de exibição da página.

Etapa 5: Adicionar suporte de classificação a uma DataList que usa paginação padrão

No tutorial anterior , examinamos como implementar a paginação padrão com um DataList. Vamos estender este exemplo anterior para incluir a capacidade de classificar os dados paginado. Comece abrindo as SortingWithDefaultPaging.aspx páginas e Paging.aspx na PagingSortingDataListRepeater pasta . Paging.aspx Na página, clique no botão Origem para exibir a marcação declarativa da página. Copie o texto selecionado (consulte Figura 8) e cole-o na marcação declarativa entre SortingWithDefaultPaging.aspx as <asp:Content> marcas.

Replicar a Marcação Declarativa nas marcas asp <:Content> de Paging.aspx para SortingWithDefaultPaging.aspx

Figura 8: Replicar a Marcação Declarativa nas <asp:Content> Marcas de Paging.aspx para SortingWithDefaultPaging.aspx (Clique para exibir a imagem em tamanho real)

Depois de copiar a marcação declarativa, copie os métodos e as propriedades na Paging.aspx classe code-behind da página para a classe code-behind para SortingWithDefaultPaging.aspx. Em seguida, reserve um momento para exibir a SortingWithDefaultPaging.aspx página em um navegador. Ele deve exibir a mesma funcionalidade e aparência que Paging.aspx.

Aprimorando productsBLL para incluir um método de paginação e classificação padrão

No tutorial anterior, criamos um GetProductsAsPagedDataSource(pageIndex, pageSize) método na ProductsBLL classe que retornava um PagedDataSource objeto . Esse PagedDataSource objeto foi preenchido com todos os produtos (por meio do método de SBLL GetProducts() ), mas quando associado à DataList apenas os registros correspondentes aos parâmetros de entrada pageIndex e pageSize especificados foram exibidos.

Anteriormente neste tutorial, adicionamos suporte à classificação especificando a expressão de classificação do manipulador de eventos ObjectDataSource Selecting . Isso funciona bem quando ObjectDataSource é retornado um objeto que pode ser classificado, como o ProductsDataTable retornado pelo GetProducts() método . No entanto, o PagedDataSource objeto retornado pelo GetProductsAsPagedDataSource método não dá suporte à classificação de sua fonte de dados interna. Em vez disso, precisamos classificar os resultados retornados do GetProducts() método antes de colocá-los no PagedDataSource.

Para fazer isso, crie um novo método na ProductsBLL classe . GetProductsSortedAsPagedDataSource(sortExpression, pageIndex, pageSize) Para classificar o ProductsDataTable retornado pelo GetProducts() método , especifique a Sort propriedade de seu padrão 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;
}

O GetProductsSortedAsPagedDataSource método difere apenas ligeiramente do GetProductsAsPagedDataSource método criado no tutorial anterior. Em particular, GetProductsSortedAsPagedDataSource aceita um parâmetro sortExpression de entrada adicional e atribui esse valor à Sort propriedade dos ProductDataTable s DefaultView. Algumas linhas de código posteriormente, o PagedDataSource objeto DataSource recebe o ProductDataTable s DefaultView.

Chamando o método GetProductsSortedAsPagedDataSource e especificando o valor para o parâmetro de entrada SortExpression

Com o GetProductsSortedAsPagedDataSource método concluído, a próxima etapa é fornecer o valor para esse parâmetro. O ObjectDataSource no SortingWithDefaultPaging.aspx está atualmente configurado para chamar o GetProductsAsPagedDataSource método e passa os dois parâmetros de entrada por meio de seus dois QueryStringParameters, que são especificados na SelectParameters coleção. Esses dois QueryStringParameters indicam que a origem dos GetProductsAsPagedDataSource parâmetros pageIndex e pageSize do método vêm dos campos pageIndex querystring e pageSize.

Atualize a propriedade ObjectDataSource para SelectMethod que ele invoque o novo GetProductsSortedAsPagedDataSource método. Em seguida, adicione um novo QueryStringParameter para que o parâmetro de entrada sortExpression seja acessado do campo sortExpressionquerystring . Defina os QueryStringParameter s DefaultValue como ProductName .

Após essas alterações, a marcação declarativa do ObjectDataSource deve ser semelhante a:

<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>

Neste ponto, a SortingWithDefaultPaging.aspx página classificará seus resultados em ordem alfabética pelo nome do produto (consulte Figura 9). Isso ocorre porque, por padrão, um valor de ProductName é passado como o GetProductsSortedAsPagedDataSource parâmetro sortExpression do método.

Por padrão, os resultados são classificados por ProductName

Figura 9: por padrão, os resultados são classificados por ProductName (clique para exibir a imagem em tamanho real)

Se você adicionar manualmente um sortExpression campo querystring, como SortingWithDefaultPaging.aspx?sortExpression=CategoryName os resultados, será classificado pelo especificado sortExpression. No entanto, esse sortExpression parâmetro não é incluído na querystring ao mover para uma página de dados diferente. Na verdade, clicar nos botões Avançar ou Última página nos leva de volta para Paging.aspx! Além disso, atualmente não há interface de classificação. A única maneira de um usuário alterar a ordem de classificação dos dados paginados é manipulando a querystring diretamente.

Criando a interface de classificação

Primeiro, precisamos atualizar o RedirectUser método para enviar o usuário para SortingWithDefaultPaging.aspx (em vez de Paging.aspx) e incluir o sortExpression valor na querystring. Também devemos adicionar uma propriedade nomeada SortExpression no nível de página somente leitura. Essa propriedade, semelhante às PageIndex propriedades e PageSize criadas no tutorial anterior, retorna o valor do sortExpression campo querystring se existir e o valor padrão ( ProductName ) caso contrário.

Atualmente, o RedirectUser método aceita apenas um único parâmetro de entrada do índice da página a ser exibido. No entanto, pode haver momentos em que queremos redirecionar o usuário para uma página específica de dados usando uma expressão de classificação diferente da especificada na cadeia de caracteres de consulta. Em um momento, criaremos a interface de classificação para esta página, que incluirá uma série de controles Da Web de botão para classificar os dados por uma coluna especificada. Quando um desses Botões é clicado, queremos redirecionar o usuário passando o valor de expressão de classificação apropriado. Para fornecer essa funcionalidade, crie duas versões do RedirectUser método . O primeiro deve aceitar apenas o índice de página a ser exibido, enquanto o segundo aceita o índice de página e a expressão de classificação.

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));
}

No primeiro exemplo deste tutorial, criamos uma interface de classificação usando um DropDownList. Para este exemplo, vamos usar três controles Web de botão posicionados acima do DataList um para classificação por ProductName, um para CategoryNamee outro para SupplierName. Adicione os três controles Web button, definindo suas ID propriedades e Text adequadamente:

<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>

Em seguida, crie um manipulador de eventos para cada um Click . Os manipuladores de eventos devem chamar o RedirectUser método , retornando o usuário para a primeira página usando a expressão de classificação apropriada.

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");
}

Ao visitar a página pela primeira vez, os dados são classificados pelo nome do produto em ordem alfabética (consulte a Figura 9). Clique no botão Avançar para avançar para a segunda página de dados e clique no botão Classificar por Categoria. Isso nos retorna à primeira página de dados, classificada pelo nome da categoria (consulte Figura 10). Da mesma forma, clicar no botão Classificar por Fornecedor classifica os dados por fornecedor a partir da primeira página de dados. A escolha de classificação é lembrada à medida que os dados são paginados. A Figura 11 mostra a página após a classificação por categoria e, em seguida, avança para a décima terceira página de dados.

Os produtos são classificados por categoria

Figura 10: Os produtos são classificados por categoria (clique para exibir a imagem em tamanho real)

A expressão de classificação é lembrada ao paginar os dados

Figura 11: a expressão de classificação é lembrada ao paginar os dados (clique para exibir a imagem em tamanho real)

Etapa 6: Paginação personalizada por meio de registros em um repetidor

O exemplo DataList examinado na etapa 5 páginas por meio de seus dados usando a técnica de paginação padrão ineficiente. Ao paginar quantidades suficientemente grandes de dados, é imperativo que a paginação personalizada seja usada. De volta aos tutoriais paginação eficiente por meio de grandes quantidades de dados e classificação de dados paginados personalizados , examinamos as diferenças entre a paginação padrão e personalizada e criamos métodos na BLL para utilizar paginação personalizada e classificar dados paginados personalizados. Em particular, nestes dois tutoriais anteriores, adicionamos os três métodos a ProductsBLL seguir à classe :

  • GetProductsPaged(startRowIndex, maximumRows) retorna um subconjunto específico de registros começando em startRowIndex e não excedendo maximumRows.
  • GetProductsPagedAndSorted(sortExpression, startRowIndex, maximumRows) retorna um subconjunto específico de registros classificados pelo parâmetro de entrada sortExpression especificado.
  • TotalNumberOfProducts() fornece o número total de registros na tabela de Products banco de dados.

Esses métodos podem ser usados para paginar e classificar com eficiência os dados usando um controle DataList ou Repeater. Para ilustrar isso, vamos começar criando um controle Repeater com suporte à paginação personalizada; Em seguida, adicionaremos recursos de classificação.

Abra a SortingWithCustomPaging.aspx página na PagingSortingDataListRepeater pasta e adicione um Repetidor à página, definindo sua ID propriedade como Products. Na marca inteligente repeater, crie um novo ObjectDataSource chamado ProductsDataSource. Configure-o para selecionar seus dados no ProductsBLL método da classe s GetProductsPaged .

Configurar o ObjectDataSource para usar o método GetProductsPaged da classe ProductsBLL

Figura 12: configurar o ObjectDataSource para usar o ProductsBLL método da GetProductsPaged classe (clique para exibir a imagem em tamanho real)

Defina as listas suspensas nas guias UPDATE, INSERT e DELETE como (Nenhum) e clique no botão Avançar. O assistente Configurar Fonte de Dados agora solicita as fontes dos parâmetros de GetProductsPaged entrada startRowIndex e maximumRows do método. Na realidade, esses parâmetros de entrada são ignorados. Em vez disso, os valores startRowIndex e maximumRows serão passados por meio da Arguments propriedade no manipulador de eventos ObjectDataSource Selecting , assim como especificamos a sortExpression na primeira demonstração deste tutorial. Portanto, deixe as listas suspensas de origem do parâmetro no conjunto de assistentes em Nenhum .

Deixe as fontes de parâmetro definidas como nenhuma

Figura 13: deixe as fontes de parâmetro definidas como nenhuma (clique para exibir a imagem em tamanho real)

Observação

Não defina a propriedade trueObjectDataSource como EnablePaging . Isso fará com que ObjectDataSource inclua automaticamente seus próprios parâmetros startRowIndex e maximumRows para a SelectMethod lista de parâmetros existente. A EnablePaging propriedade é útil ao associar dados paginados personalizados a um controle GridView, DetailsView ou FormView porque esses controles esperam determinado comportamento do ObjectDataSource que só está disponível quando EnablePaging a propriedade é true. Como temos que adicionar manualmente o suporte de paginação para DataList e Repeater, deixe essa propriedade definida false como (o padrão), pois assaremos na funcionalidade necessária diretamente em nossa página de ASP.NET.

Por fim, defina os Repeater s ItemTemplate para que o nome, a categoria e o fornecedor do produto sejam mostrados. Após essas alterações, a sintaxe declarativa de Repeater e ObjectDataSource deve ser semelhante à seguinte:

<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>

Reserve um momento para visitar a página por meio de um navegador e observe que nenhum registro é retornado. Isso ocorre porque ainda não especificamos os valores de parâmetro startRowIndex e maximumRows ; portanto, os valores de 0 estão sendo passados para ambos. Para especificar esses valores, crie um manipulador de eventos para o evento ObjectDataSource Selecting e defina esses valores de parâmetros programaticamente como valores embutidos em código de 0 e 5, respectivamente:

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

Com essa alteração, a página, quando exibida por meio de um navegador, mostra os cinco primeiros produtos.

Os cinco primeiros registros são exibidos

Figura 14: Os cinco primeiros registros são exibidos (clique para exibir a imagem em tamanho real)

Observação

Os produtos listados na Figura 14 são classificados pelo nome do produto porque o GetProductsPaged procedimento armazenado que executa a consulta de paginação personalizada eficiente ordena os resultados por ProductName.

Para permitir que o usuário percorra as páginas, precisamos acompanhar o índice de linha inicial e as linhas máximas e lembrar esses valores entre postbacks. No exemplo de paginação padrão, usamos campos querystring para persistir esses valores; para essa demonstração, vamos persistir essas informações no estado de exibição da página. Crie as duas propriedades a seguir:

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;
    }
}

Em seguida, atualize o código no manipulador de eventos Selecting para que ele use as StartRowIndex propriedades e MaximumRows em vez dos valores embutidos em código de 0 e 5:

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

Neste ponto, nossa página ainda mostra apenas os cinco primeiros registros. No entanto, com essas propriedades em vigor, estamos prontos para criar nossa interface de paginação.

Adicionando a interface de paginação

Vamos usar a mesma interface de paginação First, Previous, Next, Last usada no exemplo de paginação padrão, incluindo o controle Web Rótulo que exibe qual página de dados está sendo exibida e quantas páginas totais existem. Adicione os quatro controles Da Web de Botão e Rótulo abaixo do Repetidor.

<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>

Em seguida, crie Click manipuladores de eventos para os quatro Botões. Quando um desses Botões é clicado, precisamos atualizar o StartRowIndex e reassociar os dados ao Repetidor. O código para os botões Primeiro, Anterior e Próximo é simples o suficiente, mas para o botão Último, como determinamos o índice de linha inicial da última página de dados? Para calcular esse índice, além de poder determinar se os botões Avançar e Último devem ser habilitados, precisamos saber quantos registros no total estão sendo paginados. Podemos determinar isso chamando o ProductsBLL método da classe s TotalNumberOfProducts() . Vamos criar uma propriedade de nível de página somente leitura chamada TotalRowCount que retorna os resultados do TotalNumberOfProducts() método :

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

Com essa propriedade, agora podemos determinar o índice de linha inicial da última página. Especificamente, é o resultado inteiro do TotalRowCount menos 1 dividido por MaximumRows, multiplicado por MaximumRows. Agora podemos escrever os Click manipuladores de eventos para os quatro botões de interface de paginação:

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();
}

Por fim, precisamos desabilitar os botões Primeiro e Anterior na interface de paginação ao exibir a primeira página de dados e os botões Avançar e Último ao exibir a última página. Para fazer isso, adicione o seguinte código ao manipulador de eventos 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;

Depois de adicionar esses Click manipuladores de eventos e o código para habilitar ou desabilitar os elementos da interface de paginação com base no índice de linha inicial atual, teste a página em um navegador. Como ilustra a Figura 15, ao visitar pela primeira vez a página, os botões Primeiro e Anterior serão desabilitados. Clicar em Avançar mostra a segunda página de dados, enquanto clicar em Último exibe a página final (consulte Figuras 16 e 17). Ao exibir a última página de dados, os botões Avançar e Último são desabilitados.

Os botões Anterior e Último são desabilitados ao exibir a primeira página de produtos

Figura 15: Os botões Anterior e Último são desabilitados ao exibir a primeira página de produtos (clique para exibir a imagem em tamanho real)

A segunda página de produtos é exibida

Figura 16: a segunda página de produtos é exibida (clique para exibir a imagem em tamanho real)

Clicar em Último exibe a página final de dados

Figura 17: Clicar em Último exibe a página final de dados (clique para exibir a imagem em tamanho real)

Etapa 7: Incluindo o suporte à classificação com o repetidor de páginas personalizado

Agora que a paginação personalizada foi implementada, estamos prontos para incluir o suporte de classificação. O ProductsBLL método de classe s GetProductsPagedAndSorted tem os mesmos parâmetros de entrada startRowIndex e maximumRows que GetProductsPaged, mas permite um parâmetro de entrada sortExpression adicional. Para usar o GetProductsPagedAndSorted método de SortingWithCustomPaging.aspx, precisamos executar as seguintes etapas:

  1. Altere a propriedade GetProductsPaged ObjectDataSource de SelectMethod para GetProductsPagedAndSorted.
  2. Adicione um objeto sortExpressionParameter à coleção ObjectDataSource SelectParameters .
  3. Crie uma propriedade privada no nível SortExpression da página que persista seu valor entre postbacks por meio do estado de exibição da página.
  4. Atualize o manipulador de eventos objectDataSource Selecting para atribuir ao parâmetro sortExpression do ObjectDataSource o valor da propriedade no nível SortExpression da página.
  5. Crie a interface de classificação.

Comece atualizando a propriedade ObjectDataSource e SelectMethod adicionando uma sortExpressionParameter. Verifique se a propriedade sortExpressionParameter s Type está definida como String. Depois de concluir essas duas primeiras tarefas, a marcação declarativa do ObjectDataSource deve ser semelhante à seguinte:

<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>

Em seguida, precisamos de uma propriedade no nível SortExpression da página cujo valor é serializado para exibir o estado. Se nenhum valor de expressão de classificação tiver sido definido, use ProductName como o padrão:

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

Antes que ObjectDataSource invoque o GetProductsPagedAndSorted método, precisamos definir sortExpressionParameter para o valor da SortExpression propriedade . Selecting No manipulador de eventos, adicione a seguinte linha de código:

e.InputParameters["sortExpression"] = SortExpression;

Tudo o que resta é implementar a interface de classificação. Como fizemos no último exemplo, vamos ter a interface de classificação implementada usando três controles Da Web de botão que permitem que o usuário classifique os resultados por nome do produto, categoria ou fornecedor.

<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" />

Crie Click manipuladores de eventos para esses três controles Button. No manipulador de eventos, redefina para StartRowIndex 0, defina o SortExpression como o valor apropriado e rebine os dados para o Repetidor:

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();
}

Isso é tudo o que há para ele! Embora houvesse várias etapas para implementar a paginação e a classificação personalizadas, as etapas eram muito semelhantes às necessárias para paginação padrão. A Figura 18 mostra os produtos ao exibir a última página de dados quando classificada por categoria.

A última página de dados, classificada por categoria, é exibida

Figura 18: a última página de dados, classificada por categoria, é exibida (Clique para exibir a imagem em tamanho real)

Observação

Em exemplos anteriores, ao classificar pelo fornecedor SupplierName era usado como a expressão de classificação. No entanto, para a implementação de paginação personalizada, precisamos usar CompanyName. Isso ocorre porque o procedimento armazenado responsável por implementar a paginação GetProductsPagedAndSorted personalizada passa a expressão de classificação para o ROW_NUMBER() palavra-chave, o ROW_NUMBER() palavra-chave requer o nome da coluna real em vez de um alias. Portanto, devemos usar CompanyName (o nome da coluna na tabela) em Suppliers vez do alias usado na SELECT consulta (SupplierName) para a expressão de classificação.

Resumo

Nem o DataList nem o Repeater oferecem suporte de classificação interno, mas com um pouco de código e uma interface de classificação personalizada, essa funcionalidade pode ser adicionada. Ao implementar a classificação, mas não a paginação, a expressão de classificação pode ser especificada por meio do DataSourceSelectArguments objeto passado para o método ObjectDataSource.Select Essa DataSourceSelectArguments propriedade do SortExpression objeto pode ser atribuída no manipulador de eventos ObjectDataSource Selecting .

Para adicionar recursos de classificação a um DataList ou Repeater que já fornece suporte à paginação, a abordagem mais fácil é personalizar a Camada lógica de negócios para incluir um método que aceita uma expressão de classificação. Essas informações podem ser passadas por meio de um parâmetro no ObjectDataSource s SelectParameters.

Este tutorial conclui nosso exame de paginação e classificação com os controles DataList e Repeater. Nosso próximo e último tutorial examinará como adicionar controles Web de botão aos modelos DataList e Repeater para fornecer alguma funcionalidade personalizada iniciada pelo usuário por item.

Programação feliz!

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi David Suru. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.