Compartilhar via


Filtragem mestre/detalhe em duas páginas usando um controle de repetidor e DataList (C#)

por Scott Mitchell

Baixar PDF

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 ItemTemplatecontrole . 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).

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

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.

Cada categoria é exibida como um item de lista com marcadores

Figura 2: cada categoria é exibida como um item de lista com marcadores (clique para exibir a imagem em tamanho real)

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

Os nomes de categoria agora são vinculados a ProductsForCategoryDetails.aspx

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 ProductsInCategorycomo ID . Em seguida, na marca inteligente datalist, escolha adicionar um novo ObjectDataSource à página, nomeando-o ProductsInCategoryDataSourcecomo . 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).

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

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.

Usar a CategoryID do campo Querystring como a origem do parâmetro

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.

As bebidas são exibidas, duas por linha

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.

Informações de acesso sobre a categoria por meio do método GetCategoryByCategoryID(categoryID) da classe CategoriesBLL

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 CategoryDataSourceassistente 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, EditItemTemplatee InsertItemTemplate para o FormView. Como estamos fornecendo uma interface somente leitura, fique à vontade para remover o EditItemTemplate e InsertItemTemplateo . Além disso, fique à vontade para personalizar o do ItemTemplateFormView. 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.

As informações de categoria agora são exibidas na parte superior da página

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

Uma mensagem será exibida se não houver produtos pertencentes à categoria selecionada

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.