Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
por Scott Mitchell
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).
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 FloatLeft
Styles.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).
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 oProductsBLL
método daGetProductsByCategoryID(categoryID)
classe. Esse método retorna umProductsDataTable
objeto cujaCount
propriedade indica quantosProductsRow
s existem, que é o número de produtos para o .categoryID
Podemos criar um manipulador deItemDataBound
eventos para o Repetidor que, para cada categoria associada ao Repetidor, chama oProductsBLL
método daGetProductsByCategoryID(categoryID)
classe e inclui sua contagem na saída. - Atualize o
CategoriesDataTable
no Conjunto de Dados Tipado para incluir umaNumberOfProducts
coluna. Podemos então atualizar oGetCategories()
método noCategoriesDataTable
para incluir essas informações ou, alternativamente, deixarGetCategories()
como está e criar um novoCategoriesDataTable
método chamadoGetCategoriesAndNumberOfProducts()
.
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.
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 ItemCommand
nã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).
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 oCategoriesDataTable
eCategoriesTableAdapter
para 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).
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.
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.
Figura 7: Criar o método usando uma instrução SQL ad hoc (clique para exibir a imagem em tamanho real)
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
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 NumberOfProducts
de . 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.
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).
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).
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.
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:
- Defina a
CommandName
propriedade do LinkButton no Repetidor sItemTemplate
para algum valor (eu usei ListProducts ). Ao definir esseCommandName
valor, o evento do LinkButtonCommand
é acionado quando o LinkButton é clicado. - Defina a propriedade LinkButton como
CommandArgument
o valor do itemCategoryID
atual. - Crie um manipulador de eventos para o evento do
ItemCommand
Repetidor. No manipulador deCommandArgument
eventos, defina oCategoryProductsDataSource
parâmetro ObjectDataSource comoCategoryID
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).
Figura 14: Nenhum produto é exibido ao visitar a página pela primeira vez (clique para exibir a imagem em tamanho real)
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:
- Floatutorial um tutorial sobre elementos CSS flutuantes com CSS
- Posicionamento CSS Mais informações sobre o posicionamento de elementos com CSS
- Layout de conteúdo com HTML usando
<table>
s e outros elementos HTML para posicionamento
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.