Filtragem mestre/detalhes com duas DropDownLists (C#)

por Scott Mitchell

Baixar PDF

Este tutorial expande a relação master/detalhes para adicionar uma terceira camada, usando dois controles DropDownList para selecionar os registros pai e avô desejados.

Introdução

No tutorial anterior, examinamos como exibir um relatório de master/detalhes simples usando um único DropDownList preenchido com as categorias e um GridView mostrando os produtos que pertencem à categoria selecionada. Esse padrão de relatório funciona bem ao exibir registros que têm uma relação um-para-muitos e podem ser facilmente estendidos para trabalhar em cenários que incluem várias relações um-para-muitos. Por exemplo, um sistema de entrada de pedidos teria tabelas que correspondem a clientes, pedidos e itens de linha de pedido. Um determinado cliente pode ter vários pedidos com cada pedido que consiste em vários itens. Esses dados podem ser apresentados ao usuário com dois DropDownLists e um GridView. O primeiro DropDownList teria um item de lista para cada cliente no banco de dados com o conteúdo do segundo sendo os pedidos feitos pelo cliente selecionado. Um GridView listaria os itens de linha da ordem selecionada.

Embora o banco de dados Northwind inclua as informações canônicas de detalhes de pedido/pedido de cliente em suas Customerstabelas , Orderse Order Details , essas tabelas não são capturadas em nossa arquitetura. No entanto, ainda podemos ilustrar o uso de dois DropDownLists dependentes. O primeiro DropDownList listará as categorias e a segunda os produtos pertencentes à categoria selecionada. Em seguida, um DetailsView listará os detalhes do produto selecionado.

Etapa 1: Criando e preenchendo as categorias DropDownList

Nossa primeira meta é adicionar o DropDownList que lista as categorias. Essas etapas foram examinadas detalhadamente no tutorial anterior, mas são resumidas aqui para fins de integridade.

Abra a MasterDetailsDetails.aspx página na Filtering pasta, adicione um DropDownList à página, defina sua ID propriedade como Categoriese clique no link Configurar Fonte de Dados em sua marca inteligente. No Assistente de Configuração da Fonte de Dados, escolha adicionar uma nova fonte de dados.

Adicionar uma nova fonte de dados para o DropDownList

Figura 1: Adicionar uma nova fonte de dados para o DropDownList (clique para exibir a imagem em tamanho real)

A nova fonte de dados deve, naturalmente, ser um ObjectDataSource. Nomeie este novo ObjectDataSource CategoriesDataSource e faça com que ele invoque o CategoriesBLL método do GetCategories() objeto.

Escolha usar a classe CategoriesBLL

Figura 2: Escolha usar a CategoriesBLL classe (Clique para exibir a imagem em tamanho real)

Configurar o ObjectDataSource para usar o método GetCategories()

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

Depois de configurar o ObjectDataSource, ainda precisamos especificar qual campo de fonte de dados deve ser exibido no Categories DropDownList e qual deles deve ser configurado como o valor do item de lista. Defina o CategoryName campo como a exibição e CategoryID como o valor de cada item de lista.

Fazer com que DropDownList exiba o campo CategoryName e use CategoryID como o valor

Figura 4: Fazer com que o DropDownList exiba o CategoryName campo e use CategoryID como o valor (clique para exibir a imagem em tamanho real)

Neste ponto, temos um controle DropDownList (Categories) preenchido com os registros da Categories tabela. Quando o usuário escolher uma nova categoria do DropDownList, queremos que ocorra um postback para atualizar o dropDownList do produto que vamos criar na Etapa 2. Portanto, marcar a opção Habilitar AutoPostBack da categories marca inteligente do DropDownList.

Habilitar AutoPostBack para o DropDownList de Categorias

Figura 5: Habilitar o AutoPostBack para o Categories DropDownList (clique para exibir a imagem em tamanho real)

Etapa 2: Exibindo os produtos da categoria selecionada em uma segunda lista suspensa

Com o Categories DropDownList concluído, nossa próxima etapa é exibir um DropDownList de produtos pertencentes à categoria selecionada. Para fazer isso, adicione outro DropDownList à página chamada ProductsByCategory. Assim como no Categories DropDownList, crie um novo ObjectDataSource para o ProductsByCategory DropDownList chamado ProductsByCategoryDataSource.

Adicionar uma nova fonte de dados para o DropDownList ProductsByCategory

Figura 6: Adicionar uma nova fonte de dados para o ProductsByCategory DropDownList (clique para exibir a imagem em tamanho real)

Criar um novo objetoDataSource chamado ProductsByCategoryDataSource

Figura 7: Criar um novo objetoDataSource nomeado ProductsByCategoryDataSource (clique para exibir a imagem em tamanho real)

Como o ProductsByCategory DropDownList precisa exibir apenas os produtos que pertencem à categoria selecionada, o ObjectDataSource invoca o GetProductsByCategoryID(categoryID) método do ProductsBLL objeto .

Captura de tela da janela Configurar Fonte de Dados – productsByCategoryDataSource com ProductsBLL selecionado e o botão Avançar realçado.

Figura 8: Optar por usar a ProductsBLL classe (Clique para exibir a imagem em tamanho real)

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

Figura 9: configurar o ObjectDataSource para usar o GetProductsByCategoryID(categoryID) método (clique para exibir a imagem em tamanho real)

Na etapa final do assistente, precisamos especificar o valor do categoryID parâmetro . Atribua esse parâmetro ao item selecionado do Categories DropDownList.

Efetuar pull do valor do parâmetro categoryID das categorias DropDownList

Figura 10: efetuar pull do categoryID valor do parâmetro de Categories DropDownList (clique para exibir a imagem em tamanho real)

Com o ObjectDataSource configurado, tudo o que resta é especificar quais campos de fonte de dados são usados para a exibição e o valor dos itens do DropDownList. Exiba o ProductName campo e use o ProductID campo como o valor .

Especifique os campos de fonte de dados usados para as propriedades de texto e valor de ListItems do DropDownList

Figura 11: especifique os campos de fonte de dados usados para as propriedades e Value do Text DropDownList ListItem (clique para exibir a imagem em tamanho real)

Com ObjectDataSource e ProductsByCategory DropDownList configurados, nossa página exibirá duas DropDownLists: a primeira listará todas as categorias, enquanto a segunda listará os produtos pertencentes à categoria selecionada. Quando o usuário selecionar uma nova categoria no primeiro DropDownList, um postback será exibido e o segundo DropDownList será recuperado, mostrando os produtos que pertencem à categoria recém-selecionada. Os números 12 e 13 são mostrados MasterDetailsDetails.aspx em ação quando exibidos por meio de um navegador.

Ao visitar a página pela primeira vez, a categoria bebidas é selecionada

Figura 12: Ao visitar a página pela primeira vez, a categoria Bebidas é Selecionada (Clique para exibir a imagem em tamanho real)

Escolher uma categoria diferente exibe os produtos da nova categoria

Figura 13: Escolher uma categoria diferente exibe os produtos da nova categoria (clique para exibir a imagem em tamanho real)

Atualmente, o productsByCategory DropDownList, quando alterado, não causa um postback. No entanto, queremos que um postback ocorra depois que adicionarmos um DetailsView para exibir os detalhes do produto selecionado (Etapa 3). Portanto, marcar caixa de seleção Habilitar AutoPostBack da productsByCategory marca inteligente do DropDownList.

Habilitar o recurso AutoPostBack para os produtosByCategory DropDownList

Figura 14: Habilitar o recurso AutoPostBack para o productsByCategory DropDownList (clique para exibir a imagem em tamanho real)

Etapa 3: usando um DetailsView para exibir detalhes do produto selecionado

A etapa final é exibir os detalhes do produto selecionado em detailsView. Para fazer isso, adicione um DetailsView à página, defina sua ID propriedade como ProductDetailse crie um novo ObjectDataSource para ela. Configure este ObjectDataSource para extrair seus dados do ProductsBLL método da GetProductByProductID(productID) classe usando o valor selecionado de ProductsByCategory DropDownList para o valor do productID parâmetro .

Captura de tela da janela Configurar Fonte de Dados – productsByCategoryDataSource em que ProductsBLL está selecionado e o botão Avançar está realçado.

Figura 15: Optar por usar a ProductsBLL classe (Clique para exibir a imagem em tamanho real)

Configurar o ObjectDataSource para usar o método GetProductByProductID(productID)

Figura 16: configurar o ObjectDataSource para usar o GetProductByProductID(productID) método (clique para exibir a imagem em tamanho real)

Extrair o valor do parâmetro productID do ProductsByCategory DropDownList

Figura 17: efetuar pull do productID valor do parâmetro do ProductsByCategory DropDownList (clique para exibir a imagem em tamanho real)

Você pode optar por exibir qualquer um dos campos disponíveis no DetailsView. Optei por remover os ProductIDcampos , SupplierIDe e CategoryID reordenei e formatei os campos restantes. Além disso, limpei as propriedades e Width do Height DetailsView, permitindo que o DetailsView se expanda para a largura necessária para exibir melhor seus dados em vez de tê-los restritos a um tamanho especificado. A marcação completa aparece abaixo:

<asp:DetailsView ID="ProductDetails" runat="server"
    AutoGenerateRows="False" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" EnableViewState="False">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="Product" SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName"
          HeaderText="Category" ReadOnly="True"
          SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName"
          HeaderText="Supplier" ReadOnly="True"
          SortExpression="SupplierName" />
        <asp:BoundField DataField="QuantityPerUnit"
          HeaderText="Qty/Unit" SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice"
          DataFormatString="{0:c}" HeaderText="Price"
          HtmlEncode="False" SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock"
          HeaderText="UnitsInStock" SortExpression="Units In Stock" />
        <asp:BoundField DataField="UnitsOnOrder"
          HeaderText="UnitsOnOrder" SortExpression="Units On Order" />
        <asp:BoundField DataField="ReorderLevel"
          HeaderText="ReorderLevel" SortExpression="Reorder Level" />
        <asp:CheckBoxField DataField="Discontinued"
          HeaderText="Discontinued" SortExpression="Discontinued" />
    </Fields>
</asp:DetailsView>

Reserve um momento para experimentar a MasterDetailsDetails.aspx página em um navegador. À primeira vista, pode parecer que tudo está funcionando conforme desejado, mas há um problema sutil. Quando você escolhe uma nova categoria, o ProductsByCategory DropDownList é atualizado para incluir esses produtos para a categoria selecionada, mas o ProductDetails DetailsView continuou a mostrar as informações anteriores do produto. O DetailsView é atualizado ao escolher um produto diferente para a categoria selecionada. Além disso, se você testar completamente o suficiente, descobrirá que, se você escolher continuamente novas categorias (como escolher Bebidas do Categories DropDownList, Condiments e Confeitarias), cada outra seleção de categoria fará com que o ProductDetails DetailsView seja atualizado.

Para ajudar a concretizar esse problema, vamos examinar um exemplo específico. Quando você visita a página pela primeira vez, a categoria Bebidas é selecionada e os produtos relacionados são carregados no ProductsByCategory DropDownList. Chai é o produto selecionado e seus detalhes são exibidos no ProductDetails DetailsView, conforme mostrado na Figura 18.

Os detalhes do produto selecionado são exibidos em um DetailsView

Figura 18: Os detalhes do produto selecionado são exibidos em um DetailsView (Clique para exibir a imagem em tamanho real)

Se você alterar a seleção de categoria de Bebidas para Condimentos, ocorrerá um postback e o ProductsByCategory DropDownList será atualizado de acordo, mas o DetailsView ainda exibirá detalhes para Chai.

Os detalhes do produto selecionado anteriormente ainda são exibidos

Figura 19: Os detalhes do produto selecionado anteriormente ainda são exibidos (clique para exibir a imagem em tamanho real)

Escolher um novo produto na lista atualiza o DetailsView conforme o esperado. Se você escolher uma nova categoria depois de alterar o produto, o DetailsView novamente não será atualizado. No entanto, se, em vez de escolher um novo produto, você selecionou uma nova categoria, o DetailsView será atualizado. O que está acontecendo aqui?

O problema é um problema de tempo no ciclo de vida da página. Sempre que uma página é solicitada, ela prossegue por várias etapas como sua renderização. Em uma dessas etapas, os controles ObjectDataSource marcar para ver se algum de seus SelectParameters valores foi alterado. Nesse caso, o controle da Web de dados associado ao ObjectDataSource sabe que precisa atualizar sua exibição. Por exemplo, quando uma nova categoria é selecionada, o ProductsByCategoryDataSource ObjectDataSource detecta que seus valores de parâmetro foram alterados e o ProductsByCategory DropDownList se reassocia, obtendo os produtos para a categoria selecionada.

O problema que surge nessa situação é que o ponto no ciclo de vida da página que o ObjectDataSources marcar para parâmetros alterados ocorre antes da rea vinculação dos controles da Web de dados associados. Portanto, ao selecionar uma nova categoria, ObjectDataSource ProductsByCategoryDataSource detecta uma alteração no valor de seu parâmetro. O ObjectDataSource usado pelo ProductDetails DetailsView, no entanto, não observa essas alterações porque o ProductsByCategory DropDownList ainda não foi recuperado. Posteriormente no ciclo de vida, o ProductsByCategory DropDownList se associa novamente ao ObjectDataSource, agarrando os produtos para a categoria recém-selecionada. Embora o ProductsByCategory valor de DropDownList tenha sido alterado, ObjectDataSource ProductDetails do DetailsView já fez seu valor de parâmetro marcar; portanto, o DetailsView exibe seus resultados anteriores. Essa interação é descrita na Figura 20.

O valor de ProductsByCategory DropDownList é alterado após o objetoDataSource do ProductDetailsView verificar se há alterações

Figura 20: o ProductsByCategory valor DropDownList é alterado após o ProductDetails ObjetoDataSource do DetailsView verificar se há alterações (clique para exibir a imagem em tamanho real)

Para corrigir isso, precisamos reassociar explicitamente o ProductDetails DetailsView depois que o ProductsByCategory DropDownList tiver sido associado. Podemos fazer isso chamando o ProductDetails método DetailsView DataBind() quando o ProductsByCategory evento dropDownList DataBound é acionado. Adicione o seguinte código de manipulador de eventos à MasterDetailsDetails.aspx classe code-behind da página (consulte "Configurando programaticamente os valores de parâmetro do ObjectDataSource" para uma discussão sobre como adicionar um manipulador de eventos):

protected void ProductsByCategory_DataBound(object sender, EventArgs e)
{
    ProductDetails.DataBind();
}

Depois que essa chamada explícita para o ProductDetails método DetailsView DataBind() tiver sido adicionada, o tutorial funcionará conforme o esperado. A Figura 21 destaca como essa alteração resolveu nosso problema anterior.

O ProductDetails DetailsView é atualizado explicitamente quando o evento DataBound de ProductsByCategory DropDownList é acionado

Figura 21: O ProductDetails DetailsView é atualizado explicitamente quando o ProductsByCategory evento dropDownList DataBound é acionado (clique para exibir a imagem em tamanho real)

Resumo

O DropDownList serve como um elemento de interface do usuário ideal para relatórios de master/detalhes em que há uma relação um-para-muitos entre o master e registros de detalhes. No tutorial anterior, vimos como usar um único DropDownList para filtrar os produtos exibidos pela categoria selecionada. Neste tutorial, substituímos o GridView de produtos por um DropDownList e usamos um DetailsView para exibir os detalhes do produto selecionado. Os conceitos discutidos neste tutorial podem ser facilmente estendidos para modelos de dados que envolvem várias relações um-para-muitos, como clientes, pedidos e itens de pedido. Em geral, você sempre pode adicionar um DropDownList para cada uma das entidades "um" nas relações um para muitos.

Programação feliz!

Sobre o autor

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

Agradecimentos Especiais

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