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, analisamos como separar um relatório de master/detalhes em duas páginas. Na página "master", usamos um controle Repeater para renderizar uma lista de categorias que, quando clicadas, levarão o usuário para a página "detalhes", em que uma DataList de duas colunas mostra esses produtos pertencentes à categoria selecionada.
Introdução
No tutorial anterior, vimos como exibir relatórios master/detalhes em uma única página da Web usando DropDownLists para exibir os registros "master" e um DataList para exibir os "detalhes". Outro padrão comum usado para relatórios de master/detalhes é ter os registros master em uma página da Web e os detalhes em outra. No tutorial mestre/filtragem de detalhes anterior em duas páginas , examinamos esse padrão usando um GridView para exibir todos os fornecedores no sistema. Este GridView incluiu um HyperLinkField, que foi renderizado como um link para uma segunda página, passando o SupplierID
na querystring. A segunda página usou um GridView para listar os produtos fornecidos pelo fornecedor selecionado.
Esses relatórios de master/detalhes de duas páginas também podem ser realizados usando controles DataList e Repeater. A única diferença é que nem o DataList nem o Repeater dão suporte para o controle HyperLinkField. Em vez disso, devemos adicionar um controle Web HyperLink ou um elemento HTML de âncora (<a>
) dentro do do ItemTemplate
controle . A propriedade do NavigateUrl
HyperLink ou o atributo da href
âncora podem ser personalizados usando abordagens declarativas ou programáticas.
Neste tutorial, exploraremos um exemplo que lista as categorias em uma lista com marcadores em uma página usando um controle Repeater. Cada item de lista incluirá o nome e a descrição da categoria, com o nome da categoria exibido como um link para uma segunda página. Clicar nesse link levará o usuário para a segunda página, em que um DataList mostrará os produtos que pertencem à categoria selecionada.
Etapa 1: Exibindo as categorias em uma lista com marcadores
A primeira etapa na criação de qualquer relatório de master/detalhes é começar exibindo os registros "master". Portanto, nossa primeira tarefa é exibir as categorias na página "master". Abra a CategoryListMaster.aspx
página na DataListRepeaterFiltering
pasta, adicione um controle Repeater e, na marca inteligente, opte por adicionar um novo ObjectDataSource. Configure o novo ObjectDataSource para que ele acesse seus dados do CategoriesBLL
método da GetCategories
classe (consulte a Figura 1).
Figura 1: Configurar o ObjectDataSource para usar o CategoriesBLL
método da GetCategories
classe (clique para exibir a imagem em tamanho real)
Em seguida, defina os modelos do Repetidor de modo que ele exiba cada nome de categoria e descrição como um item em uma lista com marcadores. Ainda não vamos nos preocupar em ter cada link de categoria para a página de detalhes. Veja a seguir a marcação declarativa para Repeater e ObjectDataSource:
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="ObjectDataSource1"
EnableViewState="False">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><%# Eval("CategoryName") %> - <%# Eval("Description") %></li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Com essa marcação concluída, reserve um momento para exibir nosso progresso por meio de um navegador. Como mostra a Figura 2, o Repetidor é renderizado como uma lista com marcadores mostrando o nome e a descrição de cada categoria.
Figura 2: cada categoria é exibida como um item de lista com marcadores (clique para exibir a imagem em tamanho real)
Etapa 2: Transformando o nome da categoria em um link para a página de detalhes
Para permitir que um usuário exiba as informações de "detalhes" de uma determinada categoria, precisamos adicionar um link a cada item de lista com marcadores que, quando clicado, levará o usuário para a segunda página (ProductsForCategoryDetails.aspx
). Essa segunda página exibirá os produtos para a categoria selecionada usando um DataList. Para determinar a categoria cujo link foi clicado, precisamos passar a categoria CategoryID
clicada para a segunda página por meio de algum mecanismo. A maneira mais simples e simples de transferir dados escalares de uma página para outra é por meio da querystring, que é a opção que usaremos neste tutorial. Em particular, a ProductsForCategoryDetails.aspx
página espera que o valor selecionado categoryID
seja passado por meio de um campo querystring chamado CategoryID
. Por exemplo, para exibir os produtos para a categoria Bebidas, que tem um CategoryID
de 1, um usuário visitaria ProductsForCategoryDetails.aspx?CategoryID=1
.
Para criar um hiperlink para cada item de lista com marcadores no Repetidor, precisamos adicionar um controle Web HyperLink ou um elemento de âncora HTML (<a>
) ao ItemTemplate
. Em cenários em que o hiperlink é exibido da mesma forma para cada linha, qualquer abordagem será suficiente. Para Repetidores, prefiro usar o elemento de âncora. Para usar o elemento anchor, atualize o ItemTemplate do Repeater para:
<li>
<a href='ProductsForCategoryDetails.aspx?CategoryID=<%# Eval("CategoryID") %>'>
<%# Eval("CategoryName") %>
</a> - <%# Eval("Description") %>
</li>
Observe que o CategoryID
pode ser injetado diretamente dentro do atributo do href
elemento de âncora; no entanto, para fazer isso, certifique-se de delimitar o href
valor do atributo com apóstrofos (e aspas de anotação), uma vez que o Eval
método dentro do href
atributo delimita sua cadeia de caracteres ("CategoryID"
) com aspas. Como alternativa, um controle da Web hyperlink pode ser usado em vez disso:
<li>
<asp:HyperLink runat="server" Text='<%# Eval("CategoryName") %>'
NavigateUrl='<%# "ProductsForCategoryDetails.aspx?CategoryID=" &
Eval("CategoryID") %>'>
</asp:HyperLink>
- <%# Eval("Description") %>
</li>
Observe como a parte estática da URL — ProductsForCategoryDetails.aspx?CategoryID
— é acrescentada ao resultado de diretamente dentro da sintaxe de associação de Eval("CategoryID")
dados usando concatenação de cadeia de caracteres.
Um benefício de usar o controle HyperLink é que ele pode ser acessado programaticamente do manipulador de eventos do ItemDataBound
Repetidor, se necessário. Por exemplo, talvez você queira exibir o nome da categoria como texto em vez de como um link para categorias sem produtos associados. Esse marcar poderia ser executado programaticamente no ItemDataBound
manipulador de eventos; para categorias sem produtos associados, a propriedade do NavigateUrl
HyperLink poderia ser definida como uma cadeia de caracteres em branco, resultando, assim, na renderização desse nome de categoria específico como texto sem formatação (em vez de como um link). Consulte o tutorial Formatação de DadosList e Repetidor com base em dados para obter mais informações sobre como formatar o conteúdo de DataList e Repeater com base na lógica programática por meio do ItemDataBound
manipulador de eventos.
Se você estiver acompanhando, fique à vontade para usar o elemento de âncora ou a abordagem de controle HyperLink em sua página. Independentemente da abordagem, ao exibir a página por meio de um navegador, cada nome de categoria deve ser renderizado como um link para ProductsForCategoryDetails.aspx
, passando o valor aplicável CategoryID
(consulte a Figura 3).
Figura 3: Os nomes de categoria agora são vinculados a ProductsForCategoryDetails.aspx
(clique para exibir a imagem em tamanho real)
Etapa 3: Listando os produtos que pertencem à categoria selecionada
Com a CategoryListMaster.aspx
página concluída, estamos prontos para voltar nossa atenção para implementar a página "detalhes", ProductsForCategoryDetails.aspx
. Abra esta página, arraste um DataList da Caixa de Ferramentas para o Designer e defina sua propriedade ProductsInCategory
como ID
. Em seguida, na marca inteligente datalist, escolha adicionar um novo ObjectDataSource à página, nomeando-o ProductsInCategoryDataSource
como . Configure-o de modo que ele chame o ProductsBLL
método da GetProductsByCategoryID(categoryID)
classe; defina as listas suspensas nas guias INSERT, UPDATE e DELETE como (Nenhum).
Figura 4: Configurar o ObjectDataSource para usar o ProductsBLL
método da GetProductsByCategoryID(categoryID)
classe (clique para exibir a imagem em tamanho real)
Como o GetProductsByCategoryID(categoryID)
método aceita um parâmetro de entrada (categoryID
), o assistente Escolher Fonte de Dados nos oferece uma oportunidade de especificar a origem do parâmetro. Defina a origem do parâmetro como QueryString usando o QueryStringField CategoryID
.
Figura 5: Usar o campo CategoryID
Querystring como a origem do parâmetro (clique para exibir a imagem em tamanho real)
Como vimos nos tutoriais anteriores, depois de concluir o assistente Escolher Fonte de Dados, o Visual Studio cria automaticamente um ItemTemplate
para o DataList que lista cada nome e valor do campo de dados. Substitua esse modelo por um que liste apenas o nome, o fornecedor e o preço do produto. Além disso, defina a propriedade datalist RepeatColumns
como 2. Após essas alterações, a marcação declarativa de DataList e ObjectDataSource deve ser semelhante à seguinte:
<asp:DataList ID="ProductsInCategory" runat="server" DataKeyField="ProductID"
RepeatColumns="2" DataSourceID="ProductsInCategoryDataSource"
EnableViewState="False">
<ItemTemplate>
<h5><%# Eval("ProductName") %></h5>
<p>
Supplied by <%# Eval("SupplierName") %><br />
<%# Eval("UnitPrice", "{0:C}") %>
</p>
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="ProductsInCategoryDataSource"
OldValuesParameterFormatString="original_{0}" runat="server"
SelectMethod="GetProductsByCategoryID" TypeName="ProductsBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID" QueryStringField="CategoryID"
Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>
Para exibir essa página em ação, comece na CategoryListMaster.aspx
página; em seguida, clique em um link na lista de categorias com marcadores. Isso levará você para ProductsForCategoryDetails.aspx
, passando o CategoryID
pela querystring. O ProductsInCategoryDataSource
ObjectDataSource em ProductsForCategoryDetails.aspx
obterá apenas esses produtos para a categoria especificada e os exibirá na DataList, que renderiza dois produtos por linha. A Figura 6 mostra uma captura de tela de ProductsForCategoryDetails.aspx
ao exibir as Bebidas.
Figura 6: As bebidas são exibidas, duas por linha (clique para exibir a imagem em tamanho real)
Etapa 4: Exibindo informações de categoria no ProductsForCategoryDetails.aspx
Quando um usuário clica em uma categoria em CategoryListMaster.aspx
, ele é levado para ProductsForCategoryDetails.aspx
e mostra os produtos que pertencem à categoria selecionada. No entanto, em ProductsForCategoryDetails.aspx
não há indicações visuais sobre qual categoria foi selecionada. Um usuário que pretendia clicar em Bebidas, mas acidentalmente clicou em Condimentos, não tem como perceber seu erro depois de chegar a ProductsForCategoryDetails.aspx
. Para aliviar esse possível problema, podemos exibir informações sobre a categoria selecionada — seu nome e descrição — na parte superior da ProductsForCategoryDetails.aspx
página.
Para fazer isso, adicione um FormView acima do controle Repeater em ProductsForCategoryDetails.aspx
. Em seguida, adicione um novo ObjectDataSource à página da marca inteligente do FormView chamada CategoryDataSource
e configure-o para usar o CategoriesBLL
método da GetCategoryByCategoryID(categoryID)
classe.
Figura 7: Informações de acesso sobre a categoria por meio do CategoriesBLL
método da GetCategoryByCategoryID(categoryID)
classe (clique para exibir a imagem em tamanho real)
Assim como ocorre com o ProductsInCategoryDataSource
ObjectDataSource adicionado na Etapa 3, o CategoryDataSource
assistente Configurar Fonte de Dados nos solicita uma origem para o GetCategoryByCategoryID(categoryID)
parâmetro de entrada do método. Use exatamente as mesmas configurações de antes, definindo a origem do parâmetro como QueryString e o valor QueryStringField como CategoryID
(consulte a Figura 5).
Depois de concluir o assistente, o Visual Studio cria automaticamente um ItemTemplate
, EditItemTemplate
e InsertItemTemplate
para o FormView. Como estamos fornecendo uma interface somente leitura, fique à vontade para remover o EditItemTemplate
e InsertItemTemplate
o . Além disso, fique à vontade para personalizar o do ItemTemplate
FormView. Depois de remover os modelos supérfluos e personalizar o ItemTemplate, a marcação declarativa de FormView e ObjectDataSource deve ser semelhante à seguinte:
<asp:FormView ID="FormView1" runat="server" DataKeyNames="CategoryID"
DataSourceID="CategoryDataSource" EnableViewState="False" Width="100%">
<ItemTemplate>
<h3>
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Bind("CategoryName") %>' />
</h3>
<p>
<asp:Label ID="DescriptionLabel" runat="server"
Text='<%# Bind("Description") %>' />
</p>
</ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID="CategoryDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategoryByCategoryID" TypeName="CategoriesBLL">
<SelectParameters>
<asp:QueryStringParameter Name="categoryID" Type="Int32"
QueryStringField="CategoryID" />
</SelectParameters>
</asp:ObjectDataSource>
A Figura 8 mostra uma captura de tela ao exibir esta página por meio de um navegador.
Observação
Além do FormView, também adicionei um controle HyperLink acima do FormView que levará o usuário de volta à lista de categorias (CategoryListMaster.aspx
). Fique à vontade para colocar esse link em outro lugar ou omiti-lo completamente.
Figura 8: As informações de categoria agora são exibidas na parte superior da página (clique para exibir a imagem em tamanho real)
Etapa 5: Exibindo uma mensagem se nenhum produto pertencer à categoria selecionada
A CategoryListMaster.aspx
página lista todas as categorias no sistema, independentemente de haver produtos associados. Se um usuário clicar em uma categoria sem produtos associados, a DataList em ProductsForCategoryDetails.aspx
não será renderizada, pois sua fonte de dados não terá nenhum item. Como vimos em tutoriais anteriores, o GridView fornece uma EmptyDataText
propriedade que pode ser usada para especificar uma mensagem de texto a ser exibida se não houver registros em sua fonte de dados. Infelizmente, nem o DataList nem o Repeater têm essa propriedade.
Para exibir uma mensagem informando ao usuário que não há produtos correspondentes para a categoria selecionada, precisamos adicionar um controle Rótulo à página cuja Text
propriedade é atribuída à mensagem a ser exibida caso não haja produtos correspondentes. Em seguida, precisamos definir programaticamente sua Visible
propriedade com base em se a DataList contém ou não itens.
Para fazer isso, comece adicionando um Rótulo abaixo da DataList. Defina sua ID
propriedade como NoProductsMessage
e sua Text
propriedade como "Não há produtos para a categoria selecionada..." Em seguida, precisamos definir programaticamente a propriedade desse Rótulo Visible
com base em se algum dado estava associado ou não à ProductsInCategory
DataList. Essa atribuição deve ser feita depois que os dados tiverem sido associados ao DataList. Para GridView, DetailsView e FormView, podemos criar um manipulador de eventos para o evento do controle, que é acionado após a conclusão da DataBound
vinculação de dados. No entanto, nem o DataList nem o Repeater têm um DataBound
evento disponível.
Para este exemplo específico, podemos atribuir a propriedade do Visible
Rótulo no Page_Load
manipulador de eventos, pois os dados terão sido atribuídos ao DataList antes do evento da Load
página. No entanto, essa abordagem não funcionaria no caso geral, pois os dados do ObjectDataSource podem estar associados ao DataList posteriormente no ciclo de vida da página. Por exemplo, se os dados exibidos forem baseados no valor em outro controle, como é ao exibir um relatório de master/detalhes usando um DropDownList para manter os registros "master", os dados podem não se recuperar para o controle web de dados até o PreRender
estágio no ciclo de vida da página.
Uma solução que funcionará para todos os casos é atribuir a propriedade ao False
manipulador de ItemDataBound
eventos DataList (ou ItemCreated
) ao associar um tipo de item ou Item
AlternatingItem
.Visible
Nesse caso, sabemos que há pelo menos um item de dados na fonte de dados e, portanto, podemos ocultar o NoProductsMessage
Rótulo. Além desse manipulador de eventos, também precisamos de um manipulador de eventos para o evento datalist DataBinding
, em que inicializamos a propriedade do Visible
Rótulo para True
. Como o DataBinding
evento é acionado antes dos ItemDataBound
eventos, a propriedade do Visible
Rótulo será inicialmente definida como True
; se houver algum item de dados, no entanto, ele será definido como False
. O código a seguir implementa essa lógica:
protected void ProductsInCategory_DataBinding(object sender, EventArgs e)
{
// Show the Label
NoProductsMessage.Visible = true;
}
protected void ProductsInCategory_ItemDataBound(object sender, DataListItemEventArgs e)
{
// If we have a data item, hide the Label
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
NoProductsMessage.Visible = false;
}
Todas as categorias no banco de dados Northwind estão associadas a um ou mais produtos. Para testar esse recurso, ajustei manualmente o banco de dados Northwind para este tutorial, reatribuindo todos os produtos associados à categoria Produce (CategoryID
= 7) para a categoria Frutos do Mar (CategoryID
= 8). Isso pode ser feito no servidor Explorer escolhendo Nova Consulta e usando a seguinte UPDATE
instrução:
UPDATE Products SET
CategoryID = 8
WHERE CategoryID = 7
Depois de atualizar o banco de dados adequadamente, retorne à CategoryListMaster.aspx
página e clique no link Produzir. Como não há mais produtos pertencentes à categoria Produzir, você deverá ver a "Não há produtos para a categoria selecionada..." mensagem, conforme mostrado na Figura 9.
Figura 9: Uma mensagem será exibida se não houver produtos pertencentes à categoria selecionada (clique para exibir a imagem em tamanho real)
Resumo
Embora master/detalhes possam exibir os registros de master e detalhes em uma única página, em muitos sites eles são separados em duas páginas da Web. Neste tutorial, analisamos como implementar esse relatório de master/detalhes, tendo as categorias listadas em uma lista com marcadores usando um Repetidor na página da Web "master" e os produtos associados listados na página "detalhes". Cada item de lista na página da Web master continha um link para a página de detalhes que passou o valor da CategoryID
linha.
Na página de detalhes, a recuperação desses produtos para o fornecedor especificado foi realizada por meio do ProductsBLL
método da GetProductsByCategoryID(categoryID)
classe. O categoryID
valor do parâmetro foi especificado declarativamente usando o CategoryID
valor querystring como a origem do parâmetro. Também analisamos como exibir detalhes da categoria na página de detalhes usando um FormView e como exibir uma mensagem se não houver produtos pertencentes à categoria selecionada.
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 a...
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Zack Jones e Liz Shulok. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.