Compartilhar via


Mestre/detalhes usando uma lista com marcadores de registros mestre com um DataList de detalhes (VB)

por Scott Mitchell

Baixar PDF

Neste tutorial, compactaremos o relatório mestre/detalhado de duas páginas do tutorial anterior em uma única página, mostrando uma lista com marcadores de nomes de categorias no lado esquerdo da tela e os produtos da categoria selecionada à direita da tela.

Introdução

No tutorial anterior, vimos como separar um relatório mestre/detalhado em duas páginas. Na página mestra, usamos um controle Repeater para renderizar uma lista com marcadores de categorias. Cada nome de categoria era um hiperlink que, quando clicado, levava o usuário para a página de detalhes, onde uma DataList de duas colunas mostrava os produtos pertencentes à categoria selecionada.

Neste tutorial, compactaremos o tutorial de duas páginas em uma única página, mostrando uma lista com marcadores de nomes de categoria no lado esquerdo da tela com cada nome de categoria renderizado como um LinkButton. Clicar em um dos nomes de categoria LinkButtons induz um postback e associa os produtos da categoria selecionada a uma DataList de duas colunas à direita da tela. Além de exibir o nome de cada categoria, o Repetidor à esquerda mostra quantos produtos totais existem para uma determinada categoria (consulte a Figura 1).

O nome da categoria e o número total de produtos são exibidos à esquerda

Figura 1: O nome da categoria e o número total de produtos são exibidos à esquerda (clique para exibir a imagem em tamanho real)

Passo 1: Exibindo um repetidor na parte esquerda da tela

Para este tutorial, precisamos que a lista com marcadores de categorias apareça à esquerda dos produtos da categoria selecionada. O conteúdo de uma página da Web pode ser posicionado usando tags de parágrafo de elementos HTML padrão, espaços inseparáveis, <table> s e assim por diante ou por meio de técnicas de folha de estilo em cascata (CSS). Todos os nossos tutoriais até agora usaram técnicas CSS para posicionamento. Quando criamos a interface do usuário de navegação em nossa página mestra no tutorial Páginas mestras e navegação no site, usamos o posicionamento absoluto, indicando o deslocamento de pixel preciso para a lista de navegação e o conteúdo principal. Alternativamente, o CSS pode ser usado para posicionar um elemento à direita ou à esquerda de outro por meio de flutuação. Podemos fazer com que a lista com marcadores de categorias apareça à esquerda dos produtos da categoria selecionada flutuando o Repetidor à esquerda da Lista de Dados

Abra a CategoriesAndProducts.aspx página da DataListRepeaterFiltering pasta e adicione à página um Repetidor e uma Lista de Dados. Defina o Repetidor como ID Categories e o DataList como CategoryProducts. Vá para o modo de exibição Origem e coloque os controles Repeater e DataList em seus próprios <div> elementos. Ou seja, coloque o Repetidor dentro de um <div> elemento primeiro e, em seguida, a Lista de Dados em seu próprio <div> elemento diretamente após o Repetidor. Sua marcação neste ponto deve ser semelhante à seguinte:

<div>
    <asp:Repeater ID="Categories" runat="server">
    </asp:Repeater>
</div>
<div>
    <asp:DataList ID="CategoryProducts" runat="server">
    </asp:DataList>
</div>

Para flutuar o Repetidor à esquerda da DataList, precisamos usar o float atributo de estilo CSS, assim:

<div>
    Repeater
</div>
<div>
    DataList
</div>

O float: left; flutua o primeiro <div> elemento à esquerda do segundo. As width configurações e padding-right indicam os primeiros <div> s width e quanto preenchimento é adicionado entre o conteúdo do <div> elemento e sua margem direita. Para obter mais informações sobre elementos flutuantes em CSS, confira o Floatutorial.

Em vez de especificar a configuração de estilo diretamente por meio do atributo do primeiro <p> elemento, vamos criar uma nova classe CSS chamada FloatLeftStyles.css :style

.FloatLeft
{
    float: left;
    width: 33%;
    padding-right: 10px;
}

Então podemos substituir o <div> .<div class="FloatLeft">

Depois de adicionar a classe CSS e configurar a marcação na CategoriesAndProducts.aspx página, vá para o Designer. Você deve ver o Repetidor flutuando à esquerda da Lista de Dados (embora agora ambos apareçam apenas como caixas cinzas, já que ainda não configuramos suas fontes de dados ou modelos).

O repetidor é flutuado à esquerda da lista de dados

Figura 2: O repetidor flutua à esquerda da lista de dados (clique para exibir a imagem em tamanho real)

Etapa 2: Determinar o número de produtos para cada categoria

Com a marcação ao redor do Repetidor e da Lista de Dados concluída, estamos prontos para associar os dados da categoria ao controle Repetidor. No entanto, como mostra a lista com marcadores de categorias na Figura 1, além do nome de cada categoria, também precisamos exibir o número de produtos associados à categoria. Para acessar essas informações, podemos:

  • Determine essas informações da classe code-behind da página ASP.NET. Dado um particular categoryID , podemos determinar o número de produtos associados chamando o ProductsBLL método da GetProductsByCategoryID(categoryID) classe. Esse método retorna um ProductsDataTable objeto cuja Count propriedade indica quantos ProductsRow s existem, que é o número de produtos para o .categoryID Podemos criar um manipulador de ItemDataBound eventos para o Repetidor que, para cada categoria associada ao Repetidor, chama o ProductsBLL método da GetProductsByCategoryID(categoryID) classe e inclui sua contagem na saída.
  • Atualize o CategoriesDataTable no Conjunto de Dados Tipado para incluir uma NumberOfProducts coluna. Podemos então atualizar o GetCategories() método no CategoriesDataTable para incluir essas informações ou, alternativamente, deixar GetCategories() como está e criar um novo CategoriesDataTable método chamado GetCategoriesAndNumberOfProducts().

Vamos explorar essas duas técnicas. A primeira abordagem é mais simples de implementar, pois não precisamos atualizar a camada de acesso a dados; no entanto, requer mais comunicações com o banco de dados. A chamada para o ProductsBLL método da classe no ItemDataBound manipulador de GetProductsByCategoryID(categoryID) eventos adiciona uma chamada de banco de dados extra para cada categoria exibida no Repetidor. Com esta técnica, há chamadas de banco de dados N + 1, onde N é o número de categorias exibidas no Repetidor. Com a segunda abordagem, a contagem de produtos é retornada com informações sobre cada categoria do CategoriesBLL método da classe s GetCategories() (ou GetCategoriesAndNumberOfProducts()), resultando em apenas uma viagem ao banco de dados.

Determinando o número de produtos no manipulador de eventos ItemDataBound

Determinar o número de produtos para cada categoria no manipulador de eventos do ItemDataBound Repetidor não requer nenhuma modificação em nossa Camada de Acesso a Dados existente. Todas as modificações podem ser feitas diretamente na CategoriesAndProducts.aspx página. Comece adicionando um novo ObjectDataSource nomeado CategoriesDataSource por meio da marca inteligente do Repetidor. Em seguida, configure o CategoriesDataSource ObjectDataSource para que ele recupere seus dados do CategoriesBLL método da GetCategories() classe.

Configurar o ObjectDataSource para usar o método GetCategories() da classe CategoriesBLL

Figura 3: Configurar o ObjectDataSource para usar o método da GetCategories() classe (clique para exibir a CategoriesBLL imagem em tamanho real)

Cada item no Categories Repetidor precisa ser clicável e, quando clicado, fazer com que a CategoryProducts Lista de Dados exiba esses produtos para a categoria selecionada. Isso pode ser feito tornando cada categoria um hiperlink, vinculando de volta a essa mesma página (CategoriesAndProducts.aspx), mas passando a CategoryID querystring, assim como vimos no tutorial anterior. A vantagem dessa abordagem é que uma página que exibe produtos de uma categoria específica pode ser marcada e indexada por um mecanismo de pesquisa.

Como alternativa, podemos tornar cada categoria um LinkButton, que é a abordagem que usaremos para este tutorial. O LinkButton é renderizado no navegador do usuário como um hiperlink, mas, quando clicado, induz um postback; no postback, o DataList ObjectDataSource precisa ser atualizado para exibir os produtos pertencentes à categoria selecionada. Para este tutorial, usar um hiperlink faz mais sentido do que usar um LinkButton; no entanto, pode haver outros cenários em que o uso de um LinkButton é mais vantajoso. Embora a abordagem de hiperlink seja ideal para este exemplo, vamos explorar usando o LinkButton. Como veremos, o uso de um LinkButton apresenta alguns desafios que, de outra forma, não surgiriam com um hiperlink. Portanto, o uso de um LinkButton neste tutorial destacará esses desafios e ajudará a fornecer soluções para os cenários em que talvez queiramos usar um LinkButton em vez de um hiperlink.

Observação

Você é incentivado a repetir este tutorial usando um controle ou <a> elemento HyperLink em vez do LinkButton.

A marcação a seguir mostra a sintaxe declarativa para o Repetidor e o ObjectDataSource. Observe que os modelos do Repetidor renderizam uma lista com marcadores com cada item como um LinkButton:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"></asp:LinkButton></li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

Observação

Para este tutorial, o Repetidor deve ter seu estado de exibição habilitado (observe a omissão da sintaxe EnableViewState="False" declarativa do Repetidor). Na etapa 3, criaremos um manipulador de eventos para o evento do Repetidor ItemCommand no qual atualizaremos a coleção do DataList ObjectDataSource SelectParameters . No entanto, o Repetidor s ItemCommandnão será acionado se o estado de exibição estiver desabilitado.

O LinkButton com o ID valor da propriedade de ViewCategory não tem sua Text propriedade definida. Se quiséssemos apenas exibir o nome da categoria, teríamos definido a propriedade Text declarativamente, por meio da sintaxe de vinculação de dados, da seguinte forma:

<asp:LinkButton runat="server" ID="ViewCategory"
    Text='<%# Eval("CategoryName") %>' />

No entanto, queremos mostrar o nome da categoria e o número de produtos pertencentes a essa categoria. Essas informações podem ser recuperadas do manipulador de eventos do ItemDataBound Repetidor fazendo uma chamada para o ProductBLL método da classe e determinando quantos registros são retornados GetCategoriesByProductID(categoryID) no resultante ProductsDataTable, como ilustra o código a seguir:

Protected Sub Categories_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
    ' Make sure we're working with a data item...
    If e.Item.ItemType = ListItemType.Item OrElse _
        e.Item.ItemType = ListItemType.AlternatingItem Then
        ' Reference the CategoriesRow instance bound to this RepeaterItem
        Dim category As Northwind.CategoriesRow = _
            CType(CType(e.Item.DataItem, System.Data.DataRowView).Row, _
                Northwind.CategoriesRow)
        ' Determine how many products are in this category
        Dim productsAPI As New NorthwindTableAdapters.ProductsTableAdapter
        Dim productCount As Integer = _
            productsAPI.GetProductsByCategoryID(category.CategoryID).Count
        ' Reference the ViewCategory LinkButton and set its Text property
        Dim ViewCategory As LinkButton = _
            CType(e.Item.FindControl("ViewCategory"), LinkButton)
        ViewCategory.Text = _
            String.Format("{0} ({1:N0})", category.CategoryName, productCount)
    End If
End Sub

Começamos garantindo que estamos trabalhando com um item de dados (um cujo ItemType é Item ou AlternatingItem) e, em seguida, referenciamos a CategoriesRow instância que acabou de ser vinculada ao .RepeaterItem Em seguida, determinamos o número de produtos para essa categoria criando uma instância da ProductsBLL classe, chamando seu GetCategoriesByProductID(categoryID) método e determinando o número de registros retornados usando a Count propriedade. Por fim, o ViewCategory LinkButton no ItemTemplate é referenciado e sua Text propriedade é definida como CategoryName (NumberOfProductsInCategory), em que NumberOfProductsInCategory é formatado como um número com zero casas decimais.

Observação

Como alternativa, poderíamos ter adicionado uma função de formatação à classe code-behind da página ASP.NET que aceita uma categoria s CategoryName e CategoryID valores e retorna o CategoryName concatenado com o número de produtos na categoria (conforme determinado chamando o GetCategoriesByProductID(categoryID) método). Os resultados dessa função de formatação podem ser atribuídos declarativamente à propriedade LinkButton Text, substituindo a necessidade do manipulador de ItemDataBound eventos. Consulte os tutoriais Usando TemplateFields no Controle GridView ou Formatando a Lista de Dados e o Repetidor com Base em Dados para obter mais informações sobre como usar funções de formatação.

Depois de adicionar esse manipulador de eventos, reserve um momento para testar a página por meio de um navegador. Observe como cada categoria é listada em uma lista com marcadores, exibindo o nome da categoria e o número de produtos associados à categoria (consulte a Figura 4).

O nome e o número de produtos de cada categoria são exibidos

Figura 4: O nome e o número de produtos de cada categoria são exibidos (clique para exibir a imagem em tamanho real)

Atualizando oCategoriesDataTableeCategoriesTableAdapterpara incluir o número de produtos para cada categoria

Em vez de determinar o número de produtos para cada categoria, pois ela está vinculada ao Repetidor, podemos simplificar esse processo ajustando o CategoriesDataTable e CategoriesTableAdapter na Camada de Acesso a Dados para incluir essas informações nativamente. Para conseguir isso, devemos adicionar uma nova coluna para CategoriesDataTable conter o número de produtos associados. Para adicionar uma nova coluna a uma DataTable, abra o Conjunto de Dados Tipado (App_Code\DAL\Northwind.xsd), clique com o botão direito do mouse na DataTable a ser modificada e escolha Adicionar / Coluna. Adicione uma nova coluna ao (consulte a CategoriesDataTable Figura 5).

Adicionar uma nova coluna ao CategoriesDataSource

Figura 5: Adicionar uma nova coluna ao (clique para exibir a CategoriesDataSource imagem em tamanho real)

Isso adicionará uma nova coluna chamada Column1, que você pode alterar simplesmente digitando um nome diferente. Renomeie esta nova coluna para NumberOfProducts. Em seguida, precisamos configurar as propriedades dessa coluna. Clique na nova coluna e vá para a janela Propriedades. Altere a propriedade da DataType coluna de System.String para System.Int32 e defina a ReadOnly propriedade como True, conforme mostrado na Figura 6.

Definir as propriedades DataType e ReadOnly da nova coluna

Figura 6: Definir as DataType propriedades e ReadOnly da nova coluna

Embora agora CategoriesDataTable tenha uma NumberOfProducts coluna, seu valor não é definido por nenhuma das consultas TableAdapter correspondentes. Podemos atualizar o GetCategories() método para retornar essas informações se quisermos que essas informações sejam retornadas sempre que as informações da categoria forem recuperadas. Se, no entanto, precisarmos apenas pegar o número de produtos associados para as categorias em casos raros (como apenas para este tutorial), podemos deixar GetCategories() como está e criar um novo método que retorne essas informações. Vamos usar esta última abordagem, criando um novo método chamado GetCategoriesAndNumberOfProducts().

Para adicionar esse novo GetCategoriesAndNumberOfProducts() método, clique com o botão direito do CategoriesTableAdapter mouse e escolha Nova consulta. Isso abre o Assistente de Configuração de Consulta TableAdapter, que usamos várias vezes em tutoriais anteriores. Para esse método, inicie o assistente indicando que a consulta usa uma instrução SQL ad hoc que retorna linhas.

Criar o método usando uma instrução SQL ad hoc

Figura 7: Criar o método usando uma instrução SQL ad hoc (clique para exibir a imagem em tamanho real)

A instrução SQL retorna linhas

Figura 8: A instrução SQL retorna linhas (clique para exibir a imagem em tamanho real)

A próxima tela do assistente nos solicita a consulta a ser usada. Para retornar cada categoria s CategoryID, CategoryName, e campos Description , juntamente com o número de produtos associados à categoria, use a seguinte SELECT instrução:

SELECT CategoryID, CategoryName, Description,
       (SELECT COUNT(*) FROM Products p WHERE p.CategoryID = c.CategoryID)
            as NumberOfProducts
FROM Categories c

Especifique a consulta a ser usada

Figura 9: Especificar a consulta a ser usada (clique para exibir a imagem em tamanho real)

Observe que a subconsulta que calcula o número de produtos associados à categoria tem o alias NumberOfProductsde . Essa correspondência de nomenclatura faz com que o valor retornado por essa subconsulta seja associado à CategoriesDataTable coluna s NumberOfProducts .

Depois de inserir essa consulta, a última etapa é escolher o nome do novo método. Use FillWithNumberOfProducts e GetCategoriesAndNumberOfProducts para os padrões Preencher uma DataTable e Retornar uma DataTable, respectivamente.

Nomeie os novos métodos do TableAdapter FillWithNumberOfProducts e GetCategoriesAndNumberOfProducts

Figura 10: Nomeie os métodos FillWithNumberOfProducts do New TableAdapter e GetCategoriesAndNumberOfProducts (clique para exibir a imagem em tamanho real)

Neste ponto, a Camada de Acesso a Dados foi estendida para incluir o número de produtos por categoria. Como toda a nossa camada de apresentação roteia todas as chamadas para a DAL por meio de uma camada lógica de negócios separada, precisamos adicionar um método correspondente GetCategoriesAndNumberOfProducts à CategoriesBLL classe:

<System.ComponentModel.DataObjectMethodAttribute _
    (System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetCategoriesAndNumberOfProducts() As Northwind.CategoriesDataTable
    Return Adapter.GetCategoriesAndNumberOfProducts()
End Function

Com o DAL e o BLL concluídos, estamos prontos para vincular esses dados ao Categories Repetidor em CategoriesAndProducts.aspx! Se você já criou um ObjectDataSource para o Repetidor da seção Determinando o Número de Produtos no ItemDataBound Manipulador de Eventos, exclua esse ObjectDataSource e remova a configuração da propriedade do Repetidor DataSourceID ; também desconecte o evento do ItemDataBound Repetidor do manipulador de eventos removendo a Handles Categories.OnItemDataBound sintaxe na classe code-behind ASP.NET.

Com o Repetidor de volta em seu estado original, adicione um novo ObjectDataSource nomeado CategoriesDataSource por meio da marca inteligente do Repetidor. Configure o ObjectDataSource para usar a CategoriesBLL classe, mas em vez de fazer com que ele use o método, faça com que ele use GetCategoriesAndNumberOfProducts() (consulte a GetCategories() Figura 11).

Configurar o ObjectDataSource para usar o método GetCategoriesAndNumberOfProducts

Figura 11: Configurar o ObjectDataSource para usar o método (clique para exibir a GetCategoriesAndNumberOfProducts imagem em tamanho real)

Em seguida, atualize o ItemTemplate para que a propriedade do LinkButton Text seja atribuída declarativamente usando a sintaxe de vinculação de dados e inclua os CategoryName campos de dados e NumberOfProducts . A marcação declarativa completa para o Repeater e o CategoriesDataSource ObjectDataSource segue:

<asp:Repeater ID="Categories" runat="server" DataSourceID="CategoriesDataSource">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><asp:LinkButton runat="server" ID="ViewCategory"
                Text='<%# String.Format("{0} ({1:N0})", _
                    Eval("CategoryName"), Eval("NumberOfProducts")) %>' />
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetCategoriesAndNumberOfProducts" TypeName="CategoriesBLL">
</asp:ObjectDataSource>

A saída renderizada pela atualização do DAL para incluir uma NumberOfProducts coluna é a mesma que usar a abordagem do ItemDataBound manipulador de eventos (consulte a Figura 4 para ver uma captura de tela do Repetidor mostrando os nomes das categorias e o número de produtos).

Etapa 3: Exibindo os produtos da categoria selecionada

Neste ponto, temos o Categories Repetidor exibindo a lista de categorias junto com o número de produtos em cada categoria. O Repetidor usa um LinkButton para cada categoria que, quando clicado, causa um postback, momento em que precisamos exibir esses produtos para a categoria selecionada na CategoryProducts DataList.

Um desafio que enfrentamos é como fazer com que a DataList exiba apenas os produtos para a categoria selecionada. No tutorial Mestre/Detalhes usando um GridView mestre selecionável com um Details DetailsView, vimos como criar um GridView cujas linhas podem ser selecionadas, com os detalhes da linha selecionada sendo exibidos em um DetailsView na mesma página. O ObjectDataSource do GridView retornou informações sobre todos os produtos usando o método sGetProducts(), ProductsBLL enquanto o ObjectDataSource do DetailsView recuperou informações sobre o produto selecionado usando o GetProductsByProductID(productID) método. O productID valor do parâmetro foi fornecido declarativamente associando-o ao valor da propriedade GridView SelectedValue . Infelizmente, o Repetidor não tem uma SelectedValue propriedade e não pode servir como uma fonte de parâmetro.

Observação

Este é um daqueles desafios que aparecem ao usar o LinkButton em um Repetidor. Se tivéssemos usado um hiperlink para passar a CategoryID querystring, poderíamos usar esse campo QueryString como a origem do valor do parâmetro.

Antes de nos preocuparmos com a falta de uma SelectedValue propriedade para o Repetidor, vamos primeiro vincular o DataList a um ObjectDataSource e especificar seu ItemTemplate.

Na marca inteligente da DataList , opte por adicionar um novo ObjectDataSource nomeado CategoryProductsDataSource e configure-o para usar o ProductsBLL método da GetProductsByCategoryID(categoryID) classe. Como a Lista de Dados neste tutorial oferece uma interface somente leitura, sinta-se à vontade para definir as listas suspensas nas guias INSERT, UPDATE e DELETE como (Nenhum).

Configurar o ObjectDataSource para usar o método GetProductsByCategoryID(categoryID) da classe ProductsBLL

Figura 12: Configurar o ObjectDataSource para usar ProductsBLL o método da GetProductsByCategoryID(categoryID) classe (clique para exibir a imagem em tamanho completo)

Como o GetProductsByCategoryID(categoryID) método espera um parâmetro de entrada (categoryID), o assistente Configurar fonte de dados nos permite especificar a fonte do parâmetro. Se as categorias tivessem sido listadas em um GridView ou em um DataList, definiríamos a lista suspensa Origem do parâmetro como Control e o ControlID como o ID controle Web de dados. No entanto, como o Repetidor não tem uma SelectedValue propriedade, ele não pode ser usado como uma fonte de parâmetro. Se você verificar, verá que a lista suspensa ControlID contém apenas um controle ID``CategoryProducts, o ID da DataList.

Por enquanto, defina a lista suspensa Origem do parâmetro como Nenhum. Acabaremos atribuindo programaticamente esse valor de parâmetro quando uma categoria LinkButton for clicada no Repetidor.

Não especifique uma fonte de parâmetro para o parâmetro categoryID

Figura 13: Não especificar uma fonte de parâmetro para o parâmetro (clique para exibir a categoryID imagem em tamanho real)

Depois de concluir o assistente Configurar Fonte de Dados, o Visual Studio gera automaticamente o DataList s ItemTemplate. Substitua esse padrão ItemTemplate pelo modelo que usamos no tutorial anterior; além disso, defina a DataList propriedade como RepeatColumns 2. Depois de fazer essas alterações, a marcação declarativa para sua DataList e seu ObjectDataSource associado deve ter a seguinte aparência:

<asp:DataList ID="CategoryProducts" runat="server" DataKeyField="ProductID"
    DataSourceID="CategoryProductsDataSource" RepeatColumns="2"
    EnableViewState="False">
    <ItemTemplate>
        <h5><%# Eval("ProductName") %></h5>
        <p>
            Supplied by <%# Eval("SupplierName") %><br />
            <%# Eval("UnitPrice", "{0:C}") %>
        </p>
    </ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="CategoryProductsDataSource"
    OldValuesParameterFormatString="original_{0}"  runat="server"
    SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
    <SelectParameters>
        <asp:Parameter Name="categoryID" Type="Int32" />
    </SelectParameters>
</asp:ObjectDataSource>

Atualmente, o CategoryProductsDataSource parâmetro do categoryID ObjectDataSource nunca é definido, portanto, nenhum produto é exibido ao exibir a página. O que precisamos fazer é definir esse valor de parâmetro com base na CategoryID categoria clicada no Repetidor. Isso apresenta dois desafios: primeiro, como determinamos quando um LinkButton no Repetidor foi ItemTemplate clicado; e segundo, como podemos determinar o CategoryID da categoria correspondente cujo LinkButton foi clicado?

O LinkButton, assim como os controles Button e ImageButton, tem um Click evento e um Command evento. O Click evento foi projetado para simplesmente observar que o LinkButton foi clicado. Às vezes, no entanto, além de observar que o LinkButton foi clicado, também precisamos passar algumas informações extras para o manipulador de eventos. Se esse for o caso, o LinkButton s e CommandArgument as CommandName propriedades podem receber essas informações extras. Em seguida, quando o LinkButton é clicado, seu Command evento é acionado (em vez de seu Click evento) e o manipulador de eventos recebe os valores das CommandName propriedades and CommandArgument .

Quando um Command evento é gerado de dentro de um modelo no Repetidor, o evento do Repetidor é ItemCommand acionado e é passado os CommandName valores e CommandArgument do LinkButton clicado (ou Button ou ImageButton). Portanto, para determinar quando uma categoria LinkButton no Repetidor foi clicada, precisamos fazer o seguinte:

  1. Defina a CommandName propriedade do LinkButton no Repetidor s ItemTemplate para algum valor (eu usei ListProducts ). Ao definir esse CommandName valor, o evento do LinkButton Command é acionado quando o LinkButton é clicado.
  2. Defina a propriedade LinkButton como CommandArgument o valor do item CategoryIDatual.
  3. Crie um manipulador de eventos para o evento do ItemCommand Repetidor. No manipulador de CommandArgumenteventos, defina o CategoryProductsDataSource parâmetro ObjectDataSource como CategoryID o valor do passado.

A marcação a seguir ItemTemplate para o Repetidor de Categorias implementa as etapas 1 e 2. Observe como o CommandArgument valor é atribuído ao item de dados usando a sintaxe de vinculação de CategoryID dados:

<ItemTemplate>
    <li>
        <asp:LinkButton CommandName="ListProducts"  runat="server"
            CommandArgument='<%# Eval("CategoryID") %>' ID="ViewCategory"
            Text='<%# string.Format("{0} ({1:N0})", _
                Eval("CategoryName"), Eval("NumberOfProducts")) %>'>
        </asp:LinkButton>
    </li>
</ItemTemplate>

Sempre que criar um ItemCommand manipulador de eventos, é prudente sempre verificar primeiro o valor de entrada CommandName , pois qualquer Command evento gerado por qualquer Button, LinkButton ou ImageButton dentro do Repetidor fará com que o ItemCommand evento seja acionado. Embora atualmente tenhamos apenas um desses LinkButton agora, no futuro nós (ou outro desenvolvedor em nossa equipe) podemos adicionar controles Web de botão adicionais ao Repetidor que, quando clicados, geram o mesmo ItemCommand manipulador de eventos. Portanto, é melhor sempre verificar a CommandName propriedade e prosseguir com sua lógica programática apenas se ela corresponder ao valor esperado.

Depois de CommandName garantir que o valor passado seja igual a ListProducts, o manipulador de eventos atribui o CategoryProductsDataSource parâmetro ObjectDataSource CategoryID ao valor do passado CommandArgument. Essa modificação no ObjectDataSource faz com que o SelectParameters DataList se religue à fonte de dados, mostrando os produtos para a categoria recém-selecionada.

Protected Sub Categories_ItemCommand(source As Object, e As RepeaterCommandEventArgs) _
    Handles Categories.ItemCommand
    ' If it's the "ListProducts" command that has been issued...
    If String.Compare(e.CommandName, "ListProducts", True) = 0 Then
        ' Set the CategoryProductsDataSource ObjectDataSource's CategoryID parameter
        ' to the CategoryID of the category that was just clicked (e.CommandArgument)...
        CategoryProductsDataSource.SelectParameters("CategoryID").DefaultValue = _
            e.CommandArgument.ToString()
    End If
End Sub

Com essas adições, nosso tutorial está completo! Reserve um momento para testá-lo em um navegador. A Figura 14 mostra a tela ao visitar a página pela primeira vez. Como uma categoria ainda não foi selecionada, nenhum produto é exibido. Clicar em uma categoria, como Produzir, exibe esses produtos na categoria Produto em uma visualização de duas colunas (consulte a Figura 15).

Nenhum produto é exibido ao visitar a página pela primeira vez

Figura 14: Nenhum produto é exibido ao visitar a página pela primeira vez (clique para exibir a imagem em tamanho real)

Clicar na categoria Produzir lista os produtos correspondentes à direita

Figura 15: Clicar na categoria Produzir lista os produtos correspondentes à direita (clique para exibir a imagem em tamanho real)

Resumo

Como vimos neste tutorial e no anterior, os relatórios mestre/detalhados podem ser distribuídos em duas páginas ou consolidados em uma. No entanto, a exibição de um relatório mestre/detalhes em uma única página apresenta alguns desafios sobre a melhor forma de fazer o layout dos registros mestre e detalhados na página. No tutorial Mestre/Detalhe Usando um GridView Mestre Selecionável com um DetailsView de Detalhes, fizemos com que os registros de detalhes aparecessem acima dos registros mestres; neste tutorial, usamos técnicas de CSS para que os registros mestres flutuassem à esquerda dos detalhes.

Além de exibir relatórios mestres/detalhes, também tivemos a oportunidade de explorar como recuperar o número de produtos associados a cada categoria, bem como executar a lógica do lado do servidor quando um LinkButton (ou Button ou ImageButton) é clicado de dentro de um Repetidor.

Este tutorial conclui nosso exame de relatórios mestre/detalhados com a Lista de Dados e o Repetidor. Nosso próximo conjunto de tutoriais ilustrará como adicionar recursos de edição e exclusão ao controle DataList.

Boa programação!

Leitura Adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o autor

Scott Mitchell, autor de sete livros ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Web da Microsoft desde 1998. Scott trabalha como consultor, instrutor e escritor independente. 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 a

Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi Zack Jones. Interessado em revisar meus próximos artigos do MSDN? Em caso afirmativo, envie-me uma mensagem para mitchell@4GuysFromRolla.com.