Adicionar uma coluna de GridView de botões de opção (VB)

por Scott Mitchell

Baixar PDF

Este tutorial analisa como adicionar uma coluna de botões de opção a um controle GridView para fornecer ao usuário uma maneira mais intuitiva de selecionar uma única linha do GridView.

Introdução

O controle GridView oferece uma grande quantidade de funcionalidades internas. Ele inclui vários campos diferentes para exibir texto, imagens, hiperlinks e botões. Ele dá suporte a modelos para personalização adicional. Com alguns cliques do mouse, é possível fazer um GridView em que cada linha pode ser selecionada por meio de um botão ou habilitar a edição ou exclusão de recursos. Apesar da infinidade de recursos fornecidos, muitas vezes haverá situações em que recursos adicionais e sem suporte precisarão ser adicionados. Neste tutorial e nos próximos dois, examinaremos como aprimorar a funcionalidade do GridView para incluir recursos adicionais.

Este tutorial e o próximo se concentram em aprimorar o processo de seleção de linha. Conforme examinado no Mestre/Detalhe usando um Selectable Master GridView com um Details DetailView, podemos adicionar um CommandField ao GridView que inclui um botão Selecionar. Quando clicado, um postback é seguido e a propriedade gridView é SelectedIndex atualizada para o índice da linha cujo botão Selecionar foi clicado. No tutorial Mestre/Detalhes Usando um GridView Mestre Selecionável com um DetailView de Detalhes , vimos como usar esse recurso para exibir detalhes da linha GridView selecionada.

Embora o botão Selecionar funcione em muitas situações, ele pode não funcionar tão bem para outras pessoas. Em vez de usar um botão, dois outros elementos da interface do usuário são comumente usados para seleção: o botão de opção e a caixa de seleção. Podemos aumentar o GridView para que, em vez de um botão Selecionar, cada linha contenha um botão de opção ou caixa de seleção. Em cenários em que o usuário só pode selecionar um dos registros gridView, o botão de opção pode ser preferido em vez do botão Selecionar. Em situações em que o usuário pode potencialmente selecionar vários registros, como em um aplicativo de email baseado na Web, em que um usuário pode querer selecionar várias mensagens para excluir a caixa de seleção oferece funcionalidade que não está disponível nas interfaces do usuário do botão Selecionar ou botão de opção.

Este tutorial analisa como adicionar uma coluna de botões de opção ao GridView. O tutorial de continuação explora o uso de caixas de seleção.

Etapa 1: Criando o aprimoramento das páginas da Web gridView

Antes de começarmos a aprimorar o GridView para incluir uma coluna de botões de opção, vamos primeiro tirar um momento para criar as páginas ASP.NET em nosso projeto de site que precisaremos para este tutorial e as próximas duas. Comece adicionando uma nova pasta chamada EnhancedGridView. Em seguida, adicione as seguintes ASP.NET páginas a essa pasta, certificando-se de associar cada página à Site.master página master:

  • Default.aspx
  • RadioButtonField.aspx
  • CheckBoxField.aspx
  • InsertThroughFooter.aspx

Adicionar as páginas de ASP.NET para os tutoriais do SqlDataSource-Related

Figura 1: Adicionar as páginas de ASP.NET para os tutoriais do SqlDataSource-Related

Assim como nas outras pastas, Default.aspx na EnhancedGridView pasta listará os tutoriais em sua seção. Lembre-se de que o SectionLevelTutorialListing.ascx Controle de Usuário fornece essa funcionalidade. Portanto, adicione esse Controle de Usuário ao Default.aspx arrastando-o do Gerenciador de Soluções para o modo design da página.

Adicione o controle de usuário SectionLevelTutorialListing.ascx ao Default.aspx

Figura 2: Adicionar o controle de SectionLevelTutorialListing.ascx usuário a Default.aspx (clique para exibir a imagem em tamanho real)

Por fim, adicione essas quatro páginas como entradas ao Web.sitemap arquivo. Especificamente, adicione a seguinte marcação após Usar o controle <siteMapNode>SqlDataSource :

<siteMapNode 
    title="Enhancing the GridView" 
    url="~/EnhancedGridView/Default.aspx" 
    description="Augment the user experience of the GridView control.">
    <siteMapNode 
        url="~/EnhancedGridView/RadioButtonField.aspx" 
        title="Selection via a Radio Button Column" 
        description="Explore how to add a column of radio buttons in the GridView." />
    <siteMapNode 
        url="~/EnhancedGridView/CheckBoxField.aspx" 
        title="Selection via a Checkbox Column" 
        description="Select multiple records in the GridView by using a column of 
            checkboxes." />
    <siteMapNode 
        url="~/EnhancedGridView/InsertThroughFooter.aspx" 
        title="Add New Records through the Footer" 
        description="Learn how to allow users to add new records through the 
            GridView's footer." />
</siteMapNode>

Depois de atualizar Web.sitemap, reserve um momento para exibir o site de tutoriais por meio de um navegador. O menu à esquerda agora inclui itens para os tutoriais de edição, inserção e exclusão.

O mapa do site agora inclui entradas para o aprimoramento dos tutoriais do GridView

Figura 3: O mapa do site agora inclui entradas para os tutoriais de Aprimoramento do GridView

Etapa 2: Exibindo os fornecedores em um GridView

Para este tutorial, vamos criar um GridView que lista os fornecedores dos EUA, com cada linha GridView fornecendo um botão de opção. Depois de selecionar um fornecedor por meio do botão de opção, o usuário pode exibir os produtos do fornecedor clicando em um botão. Embora essa tarefa possa soar trivial, há uma série de sutilezas que a tornam particularmente complicada. Antes de nos aprofundarmos nessas sutilezas, vamos primeiro obter um GridView listando os fornecedores.

Comece abrindo a RadioButtonField.aspx página na EnhancedGridView pasta arrastando um GridView da Caixa de Ferramentas para o Designer. Defina GridView s ID como Suppliers e, de sua marca inteligente, escolha criar uma nova fonte de dados. Especificamente, crie um ObjectDataSource chamado SuppliersDataSource que extraia seus dados do SuppliersBLL objeto .

Criar um novo objectDataSource chamado SuppliersDataSource

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

Captura de tela da janela Configurar Fonte de Dados – SuppliersDataSource com o menu suspenso do objeto comercial aberto. SuppliersBLL está selecionado e o botão Avançar está realçado.

Figura 5: Configurar o ObjectDataSource para usar a SuppliersBLL classe (clique para exibir a imagem em tamanho real)

Como só queremos listar esses fornecedores nos EUA, escolha o GetSuppliersByCountry(country) método na lista suspensa na guia SELECT.

Captura de tela da janela Configurar Fonte de Dados – SuppliersDataSource na guia SELECT com o menu suspenso do método aberto. A opção de método GetSupplierByCountry está selecionada e o botão Avançar está realçado.

Figura 6: Configurar o ObjectDataSource para usar a SuppliersBLL classe (clique para exibir a imagem em tamanho real)

Na guia UPDATE, selecione a opção (Nenhum) e clique em Avançar.

Captura de tela da janela Configurar Fonte de Dados – SuppliersDataSource na guia UPDATE com o menu suspenso do método aberto. A opção de método (Nenhum) está selecionada e o botão Avançar está realçado.

Figura 7: Configurar o ObjectDataSource para usar a SuppliersBLL classe (clique para exibir a imagem em tamanho real)

Como o GetSuppliersByCountry(country) método aceita um parâmetro, o assistente Configurar Fonte de Dados nos solicita a origem desse parâmetro. Para especificar um valor embutido em código (EUA, neste exemplo), deixe a lista suspensa Origem do parâmetro definida como Nenhum e insira o valor padrão na caixa de texto. Clique em Concluir para concluir o assistente.

Usar USA como o valor padrão para o parâmetro country

Figura 8: Usar EUA como o valor padrão para o country parâmetro (clique para exibir a imagem em tamanho real)

Depois de concluir o assistente, o GridView incluirá um BoundField para cada um dos campos de dados do fornecedor. Remova todos, exceto , CompanyNameCitye Country BoundFields, e renomeie a CompanyName propriedade BoundFields HeaderText como Supplier. Depois de fazer isso, a sintaxe declarativa GridView e ObjectDataSource deve ser semelhante à seguinte.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
    <SelectParameters>
        <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

Para este tutorial, vamos permitir que o usuário exiba os produtos do fornecedor selecionado na mesma página que a lista de fornecedores ou em uma página diferente. Para acomodar isso, adicione dois controles Da Web de botão à página. Defina os ID s desses dois Botões como ListProducts e SendToProducts, com a ideia de que quando ListProducts for clicado um postback ocorrerá e os produtos do fornecedor selecionado serão listados na mesma página, mas quando SendToProducts for clicado, o usuário será levado para outra página que lista os produtos.

A Figura 9 mostra o Suppliers GridView e os dois controles da Web de botão quando exibidos por meio de um navegador.

Esses fornecedores dos EUA têm suas informações de nome, cidade e país listadas

Figura 9: Os fornecedores dos EUA têm suas informações de nome, cidade e país listadas (clique para exibir a imagem em tamanho real)

Etapa 3: Adicionar uma coluna de botões de opção

Neste ponto, o Suppliers GridView tem três BoundFields exibindo o nome da empresa, a cidade e o país de cada fornecedor nos EUA. No entanto, ainda falta uma coluna de botões de opção. Infelizmente, o GridView não inclui um RadioButtonField interno, caso contrário, poderíamos apenas adicioná-lo à grade e ser feito. Em vez disso, podemos adicionar um TemplateField e configurá-lo ItemTemplate para renderizar um botão de opção, resultando em um botão de opção para cada linha gridView.

Inicialmente, podemos supor que a interface do usuário desejada possa ser implementada adicionando um controle Web RadioButton ao ItemTemplate de um TemplateField. Embora isso realmente adicione um único botão de opção a cada linha do GridView, os botões de opção não podem ser agrupados e, portanto, não são mutuamente exclusivos. Ou seja, um usuário final pode selecionar vários botões de opção simultaneamente no GridView.

Embora o uso de um TemplateField de controles da Web RadioButton não ofereça a funcionalidade necessária, vamos implementar essa abordagem, pois vale a pena examinar por que os botões de opção resultantes não são agrupados. Comece adicionando um TemplateField ao Suppliers GridView, tornando-o o campo mais à esquerda. Em seguida, na marca inteligente GridView, clique no link Editar Modelos e arraste um controle Web RadioButton da Caixa de Ferramentas para o TemplateField s ItemTemplate (consulte a Figura 10). Defina a propriedade RadioButton como ID e a GroupName propriedade como SuppliersGroup.RowSelector

Adicionar um controle Web RadioButton ao ItemTemplate

Figura 10: Adicionar um controle Web RadioButton ao ItemTemplate (Clique para exibir a imagem em tamanho real)

Depois de fazer essas adições por meio do Designer, a marcação do GridView deve ser semelhante à seguinte:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:RadioButton ID="RowSelector" runat="server" 
                    GroupName="SuppliersGroup" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>

A propriedade RadioButton s GroupName é usada para agrupar uma série de botões de opção. Todos os controles RadioButton com o mesmo GroupName valor são considerados agrupados; somente um botão de opção pode ser selecionado de um grupo por vez. A GroupName propriedade especifica o valor do atributo do botão de name opção renderizado. O navegador examina os atributos de botões name de opção para determinar os agrupamentos de botões de opção.

Com o controle Web RadioButton adicionado ao ItemTemplate, visite esta página por meio de um navegador e clique nos botões de opção nas linhas da grade. Observe como os botões de opção não são agrupados, tornando possível selecionar todas as linhas, como mostra a Figura 11.

Os botões de opção gridview não estão agrupados

Figura 11: Os botões de opção GridView não estão agrupados (clique para exibir a imagem em tamanho real)

O motivo pelo qual os botões de opção não são agrupados é porque seus atributos renderizados name são diferentes, apesar de terem a mesma GroupName configuração de propriedade. Para ver essas diferenças, faça uma Exibição/Fonte do navegador e examine a marcação do botão de opção:

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
    type="radio" value="RowSelector" />

Observe como os name atributos e id não são os valores exatos, conforme especificado no janela Propriedades, mas são precedidos por vários outros ID valores. Os valores adicionais ID adicionados à frente dos atributos renderizados id e name são os ID s dos botões de opção pai controla os GridViewRow s ID , o GridView s ID, o Controle de conteúdo s IDe o Web Form s ID. Esses ID s são adicionados para que cada controle da Web renderizado no GridView tenha valores e name exclusivosid.

Cada controle renderizado precisa de um diferente name e id porque é assim que o navegador identifica exclusivamente cada controle no lado do cliente e como ele identifica para o servidor Web qual ação ou alteração ocorreu no postback. Por exemplo, imagine que queríamos executar algum código do lado do servidor sempre que um estado verificado do RadioButton fosse alterado. Podemos fazer isso definindo a propriedade True RadioButton como AutoPostBack e criando um manipulador de eventos para o CheckChanged evento. No entanto, se os valores renderizados name e id para todos os botões de opção forem os mesmos, no postback não foi possível determinar qual RadioButton específico foi clicado.

Resumindo, não é possível criar uma coluna de botões de opção em um GridView usando o controle Web RadioButton. Em vez disso, devemos usar técnicas bastante arcaicas para garantir que a marcação apropriada seja injetada em cada linha gridView.

Observação

Assim como o controle Da Web RadioButton, o controle HTML do botão de opção, quando adicionado a um modelo, incluirá o atributo exclusivo name , tornando os botões de opção na grade desagrupados. Se você não estiver familiarizado com controles HTML, fique à vontade para ignorar essa observação, pois os controles HTML raramente são usados, especialmente no ASP.NET 2.0. Mas se você estiver interessado em aprender mais, consulte K. Scott Allen entrada de blog Controles web e controles HTML.

Usando um controle literal para injetar marcação de botão de opção

Para agrupar corretamente todos os botões de opção no GridView, precisamos injetar manualmente a marcação de botões de opção no ItemTemplate. Cada botão de opção precisa do mesmo name atributo, mas deve ter um atributo exclusivo id (caso queiramos acessar um botão de opção por meio do script do lado do cliente). Depois que um usuário selecionar um botão de opção e postar de volta a página, o navegador enviará de volta o valor do atributo do botão de value opção selecionado. Portanto, cada botão de opção precisará de um atributo exclusivo value . Por fim, no postback, precisamos adicionar o checked atributo a um botão de opção selecionado; caso contrário, depois que o usuário fizer uma seleção e postar de volta, os botões de opção retornarão ao estado padrão (todos não selecionados).

Há duas abordagens que podem ser tomadas para injetar marcação de baixo nível em um modelo. Uma delas é fazer uma combinação de marcação e chamadas para métodos de formatação definidos na classe code-behind. Essa técnica foi discutida pela primeira vez no tutorial Usando TemplateFields no Controle GridView . Em nosso caso, pode ser algo parecido com:

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
    name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

Aqui, GetUniqueRadioButton e GetRadioButtonValue seriam métodos definidos na classe code-behind que retornavam os valores de atributo e value apropriados id para cada botão de opção. Essa abordagem funciona bem para atribuir os id atributos e value , mas fica aquém ao precisar especificar o valor do checked atributo porque a sintaxe de associação de dados só é executada quando os dados são associados pela primeira vez ao GridView. Portanto, se o GridView tiver o estado de exibição habilitado, os métodos de formatação só serão acionados quando a página for carregada pela primeira vez (ou quando o GridView for explicitamente recuperado para a fonte de dados) e, portanto, a função que define o checked atributo não será chamada no postback. É um problema bastante sutil e um pouco além do escopo deste artigo, então vou deixá-lo com isso. No entanto, eu encorajo você a tentar usar a abordagem acima e trabalhar até o ponto em que você vai ficar preso. Embora esse exercício não o aproxime de uma versão funcional, ele ajudará a promover uma compreensão mais profunda do GridView e do ciclo de vida de vinculação de dados.

A outra abordagem para injetar marcação personalizada de baixo nível em um modelo e a abordagem que usaremos para este tutorial é adicionar um controle Literal ao modelo. Em seguida, no manipulador de eventos ou RowCreatedRowDataBound GridView, o controle Literal pode ser acessado programaticamente e sua Text propriedade definida como a marcação a ser emitida.

Comece removendo o RadioButton do TemplateField s ItemTemplate, substituindo-o por um controle Literal. Defina o controle literal s ID como RadioButtonMarkup.

Adicionar um controle literal ao ItemTemplate

Figura 12: Adicionar um controle literal ao ItemTemplate (clique para exibir a imagem em tamanho real)

Em seguida, crie um manipulador de eventos para o evento GridView.RowCreated O RowCreated evento é acionado uma vez para cada linha adicionada, independentemente de os dados estarem sendo recuperados ou não para o GridView. Isso significa que, mesmo em um postback quando os dados são recarregados do estado de exibição, o RowCreated evento ainda é acionado e esse é o motivo pelo qual estamos usando-o em vez de RowDataBound (que é acionado somente quando os dados são explicitamente associados ao controle da Web de dados).

Nesse manipulador de eventos, só queremos continuar se estivermos lidando com uma linha de dados. Para cada linha de dados, queremos referenciar programaticamente o RadioButtonMarkup controle Literal e definir sua Text propriedade como a marcação a ser emitida. Como mostra o código a seguir, a marcação emitida cria um botão de opção cujo name atributo é definido SuppliersGroupcomo , cujo id atributo é definido RowSelectorXcomo , em que X é o índice da linha GridView e cujo value atributo é definido como o índice da linha GridView.

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' Output the markup except for the "checked" attribute
        output.Text = String.Format( _
            "<input type="radio" name="SuppliersGroup" " & _
            "id="RowSelector{0}" value="{0}" />", e.Row.RowIndex)
    End If
End Sub

Quando uma linha GridView é selecionada e ocorre um postback, estamos interessados no SupplierID do fornecedor selecionado. Portanto, pode-se pensar que o valor de cada botão de opção deve ser o real SupplierID (em vez do índice da linha GridView). Embora isso possa funcionar em determinadas circunstâncias, seria um risco de segurança aceitar e processar cegamente um SupplierID. Nosso GridView, por exemplo, lista apenas os fornecedores nos EUA. No entanto, se o SupplierID for passado diretamente do botão de opção, o que impedirá um usuário travesso de manipular o SupplierID valor enviado de volta no postback? Usando o índice de linha como e value, em seguida, obtendo o SupplierID no postback da DataKeys coleção, podemos garantir que o usuário esteja usando apenas um dos SupplierID valores associados a uma das linhas GridView.

Depois de adicionar esse código do manipulador de eventos, reserve um minuto para testar a página em um navegador. Primeiro, observe que apenas um botão de opção na grade pode ser selecionado por vez. No entanto, ao selecionar um botão de opção e clicar em um dos botões, um postback ocorre e os botões de opção reverter ao estado inicial (ou seja, no postback, o botão de opção selecionado não está mais selecionado). Para corrigir isso, precisamos aumentar o RowCreated manipulador de eventos para que ele inspecione o índice de botão de opção selecionado enviado do postback e adicione o checked="checked" atributo à marcação emitida das correspondências de índice de linha.

Quando ocorre um postback, o navegador envia de volta o name e value o do botão de opção selecionado. O valor pode ser recuperado programaticamente usando Request.Form("name"). A Request.Form propriedade fornece um NameValueCollection que representa as variáveis de formulário. As variáveis de formulário são os nomes e valores dos campos de formulário na página da Web e são enviadas de volta pelo navegador da Web sempre que um postback ocorre. Como o atributo renderizado name dos botões de opção no GridView é SuppliersGroup, quando a página da Web é postada de volta, o navegador enviará SuppliersGroup=valueOfSelectedRadioButton de volta para o servidor Web (juntamente com os outros campos de formulário). Essas informações podem ser acessadas da Request.Form propriedade usando: Request.Form("SuppliersGroup").

Como precisaremos determinar o índice do botão de opção selecionado não apenas no RowCreated manipulador de eventos, mas nos Click manipuladores de eventos para os controles da Web button, vamos adicionar uma SuppliersSelectedIndex propriedade à classe code-behind que retorna -1 se nenhum botão de opção foi selecionado e o índice selecionado se um dos botões de opção estiver selecionado.

Private ReadOnly Property SuppliersSelectedIndex() As Integer
    Get
        If String.IsNullOrEmpty(Request.Form("SuppliersGroup")) Then
            Return -1
        Else
            Return Convert.ToInt32(Request.Form("SuppliersGroup"))
        End If
    End Get
End Property

Com essa propriedade adicionada, sabemos adicionar a checked="checked" marcação no RowCreated manipulador de eventos quando SuppliersSelectedIndex for igual e.Row.RowIndexa . Atualize o manipulador de eventos para incluir essa lógica:

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' Output the markup except for the "checked" attribute
        output.Text = String.Format( _
            "<input type="radio" name="SuppliersGroup" " & _
            "id="RowSelector{0}" value="{0}"", e.Row.RowIndex)
        ' See if we need to add the "checked" attribute
        If SuppliersSelectedIndex = e.Row.RowIndex Then
            output.Text &= " checked="checked""
        End If
        ' Add the closing tag
        output.Text &= " />"
    End If
End Sub

Com essa alteração, o botão de opção selecionado permanece selecionado após um postback. Agora que temos a capacidade de especificar qual botão de opção está selecionado, podemos alterar o comportamento para que, quando a página foi visitada pela primeira vez, o primeiro botão de opção da linha GridView tenha sido selecionado (em vez de não ter botões de opção selecionados por padrão, que é o comportamento atual). Para que o primeiro botão de opção seja selecionado por padrão, basta alterar a If SuppliersSelectedIndex = e.Row.RowIndex Then instrução para o seguinte: If SuppliersSelectedIndex = e.Row.RowIndex OrElse (Not Page.IsPostBack AndAlso e.Row.RowIndex = 0) Then.

Neste ponto, adicionamos uma coluna de botões de opção agrupados ao GridView que permite que uma única linha GridView seja selecionada e lembrada entre postbacks. Nossas próximas etapas são exibir os produtos fornecidos pelo fornecedor selecionado. Na Etapa 4, veremos como redirecionar o usuário para outra página, enviando ao longo do selecionado SupplierID. Na Etapa 5, veremos como exibir os produtos do fornecedor selecionado em um GridView na mesma página.

Observação

Em vez de usar um TemplateField (o foco desta longa Etapa 3), poderíamos criar uma classe personalizada DataControlField que renderiza a interface do usuário e a funcionalidade apropriadas. A DataControlField classe é a classe base da qual os campos BoundField, CheckBoxField, TemplateField e outros campos internos GridView e DetailsView derivam. Criar uma classe personalizada DataControlField significaria que a coluna de botões de opção poderia ser adicionada apenas usando sintaxe declarativa e também facilitaria significativamente a replicação da funcionalidade em outras páginas da Web e em outros aplicativos Web.

Se você já criou controles personalizados e compilados em ASP.NET, no entanto, você sabe que isso requer uma boa quantidade de trabalho e carrega consigo uma série de sutilezas e casos de borda que devem ser cuidadosamente tratados. Portanto, vamos renunciar à implementação de uma coluna de botões de opção como uma classe personalizada DataControlField por enquanto e ficar com a opção TemplateField. Talvez tenhamos a chance de explorar a criação, o uso e a implantação de classes personalizadas DataControlField em um tutorial futuro!

Etapa 4: Exibindo os produtos do fornecedor selecionado em uma página separada

Depois que o usuário tiver selecionado uma linha GridView, precisaremos mostrar os produtos do fornecedor selecionado. Em algumas circunstâncias, talvez queiramos exibir esses produtos em uma página separada, em outras, talvez prefira fazê-lo na mesma página. Primeiro, vamos examinar como exibir os produtos em uma página separada; Na Etapa 5, examinaremos a adição de um GridView para RadioButtonField.aspx exibir os produtos do fornecedor selecionado.

Atualmente, há dois controles Da Web de botão na página ListProducts e SendToProducts. Quando o SendToProducts Botão é clicado, queremos enviar o usuário para ~/Filtering/ProductsForSupplierDetails.aspx. Esta página foi criada no tutorial Filtragem Mestre/Detalhes em Duas Páginas e exibe os produtos para o fornecedor cujo SupplierID é passado pelo campo querystring chamado SupplierID.

Para fornecer essa funcionalidade, crie um manipulador de eventos para o SendToProducts evento Do Click botão. Na Etapa 3, adicionamos a SuppliersSelectedIndex propriedade , que retorna o índice da linha cujo botão de opção está selecionado. O correspondente SupplierID pode ser recuperado da coleção GridView e DataKeys , em seguida, o usuário pode ser enviado para ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID usando Response.Redirect("url").

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    Dim supplierID As Integer = _
        Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
    Response.Redirect( _
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
        supplierID)
End Sub

Esse código funciona maravilhosamente, desde que um dos botões de opção seja selecionado no GridView. Se, inicialmente, o GridView não tiver nenhum botão de opção selecionado e o usuário clicar no botão, SuppliersSelectedIndex será , o SendToProducts que fará com que uma exceção seja gerada, pois -1 está fora do intervalo de índice da DataKeys coleção-1. No entanto, isso não é uma preocupação se você decidiu atualizar o RowCreated manipulador de eventos conforme discutido na Etapa 3 para que o primeiro botão de opção no GridView seja selecionado inicialmente.

Para acomodar um SuppliersSelectedIndex valor de -1, adicione um controle Web Label à página acima do GridView. Defina sua ID propriedade ChooseSupplierMsgcomo , sua CssClass propriedade como Warning, suas EnableViewState propriedades Falsee Visible como e sua Text propriedade como Por favor, escolha um fornecedor na grade. A classe Warning CSS exibe texto em uma fonte vermelha, itálica, negrito, grande e é definida em Styles.css. Ao definir as EnableViewState propriedades e Visible como False, o Rótulo não é renderizado, exceto apenas para os postbacks em que a propriedade s do Visible controle é definida Trueprogramaticamente como .

Adicionar um controle Web de rótulo acima do GridView

Figura 13: Adicionar um controle Web de rótulo acima do GridView (clique para exibir a imagem em tamanho real)

Em seguida, aumente o Click manipulador de eventos para exibir o ChooseSupplierMsg Rótulo se SuppliersSelectedIndex for menor que zero e redirecione o usuário para ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID o contrário.

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
    Else
        ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        Dim supplierID As Integer = _
            Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
        Response.Redirect( _
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
            supplierID)
    End If
End Sub

Visite a página em um navegador e clique no SendToProducts botão antes de selecionar um fornecedor no GridView. Como mostra a Figura 14, isso exibe o ChooseSupplierMsg rótulo. Em seguida, selecione um fornecedor e clique no SendToProducts botão. Isso levará você a uma página que lista os produtos fornecidos pelo fornecedor selecionado. A Figura 15 mostra a ProductsForSupplierDetails.aspx página quando o fornecedor das Cervejarias Bigfoot foi selecionado.

O rótulo ChooseSupplierMsg será exibido se nenhum fornecedor estiver selecionado

Figura 14: o ChooseSupplierMsg rótulo será exibido se nenhum fornecedor estiver selecionado (clique para exibir a imagem em tamanho real)

Os produtos do fornecedor selecionado são exibidos em ProductsForSupplierDetails.aspx

Figura 15: Os produtos do fornecedor selecionado são exibidos em ProductsForSupplierDetails.aspx (Clique para exibir a imagem em tamanho real)

Etapa 5: Exibindo os produtos do fornecedor selecionado na mesma página

Na Etapa 4, vimos como enviar o usuário para outra página da Web para exibir os produtos do fornecedor selecionado. Como alternativa, os produtos do fornecedor selecionado podem ser exibidos na mesma página. Para ilustrar isso, adicionaremos outro GridView para RadioButtonField.aspx exibir os produtos do fornecedor selecionado.

Como só queremos que esse GridView de produtos seja exibido depois que um fornecedor tiver sido selecionado, adicione um controle Web painel abaixo do GridView, definindo-o SuppliersID como ProductsBySupplierPanel e sua Visible propriedade como False. No Painel, adicione o texto Produtos para o Fornecedor Selecionado, seguido por um GridView chamado ProductsBySupplier. Na marca inteligente GridView, escolha associá-la a um novo ObjectDataSource chamado ProductsBySupplierDataSource.

Associar o ProductsBySupplier GridView a um Novo ObjetoDataSource

Figura 16: Associar o ProductsBySupplier GridView a um Novo ObjetoDataSource (Clique para exibir a imagem em tamanho real)

Em seguida, configure o ObjectDataSource para usar a ProductsBLL classe . Como só queremos recuperar esses produtos fornecidos pelo fornecedor selecionado, especifique que ObjectDataSource deve invocar o GetProductsBySupplierID(supplierID) método para recuperar seus dados. Selecione (Nenhum) nas listas suspensas nas guias UPDATE, INSERT e DELETE.

Configurar o ObjectDataSource para usar o método GetProductsBySupplierID(supplierID)

Figura 17: configurar o ObjectDataSource para usar o GetProductsBySupplierID(supplierID) método (clique para exibir a imagem em tamanho real)

Defina o Drop-Down Listas como (Nenhum) nas guias UPDATE, INSERT e DELETE

Figura 18: defina o Drop-Down Listas como (Nenhum) nas guias UPDATE, INSERT e DELETE (Clique para exibir a imagem em tamanho real)

Depois de configurar as guias SELECT, UPDATE, INSERT e DELETE, clique em Avançar. Como o GetProductsBySupplierID(supplierID) método espera um parâmetro de entrada, o assistente Criar Fonte de Dados solicita que especifiquemos a origem do valor do parâmetro.

Temos algumas opções aqui para especificar a origem do valor do parâmetro. Poderíamos usar o objeto Parameter padrão e atribuir programaticamente o valor da SuppliersSelectedIndex propriedade à propriedade Parameter no DefaultValue manipulador de eventos ObjectDataSource Selecting . Consulte o tutorial Definindo programaticamente os valores de parâmetro do ObjectDataSource para um atualizador sobre como atribuir valores programaticamente aos parâmetros objectDataSource.

Como alternativa, podemos usar um ControlParameter e consultar a Suppliers propriedade GridView (SelectedValueconsulte a Figura 19). A propriedade GridView SelectedValue retorna o DataKey valor correspondente à SelectedIndex propriedade . Para que essa opção funcione, precisamos definir programaticamente a propriedade GridView como SelectedIndex a linha selecionada quando o ListProducts botão for clicado. Como um benefício adicional, definindo o SelectedIndex, o registro selecionado assumirá o SelectedRowStyle definido no DataWebControls Tema (uma tela de fundo amarela).

Usar um ControlParameter para especificar SelectedValue do GridView como a origem do parâmetro

Figura 19: use um ControlParameter para especificar SelectedValue do GridView como a origem do parâmetro (clique para exibir a imagem em tamanho real)

Ao concluir o assistente, o Visual Studio adicionará automaticamente campos para os campos de dados do produto. Remova todos, exceto , ProductNameCategoryNamee UnitPrice BoundFields, e altere as HeaderText propriedades para Product, Category e Price. Configure o UnitPrice BoundField para que seu valor seja formatado como uma moeda. Depois de fazer essas alterações, a marcação declarativa de Panel, GridView e ObjectDataSource deve ser semelhante à seguinte:

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
    <h3>
        Products for the Selected Supplier</h3>
    <p>
        <asp:GridView ID="ProductsBySupplier" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
            <Columns>
                <asp:BoundField DataField="ProductName" HeaderText="Product" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                    ReadOnly="True" SortExpression="CategoryName" />
                <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                    HeaderText="Price" HtmlEncode="False" 
                    SortExpression="UnitPrice" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
            <SelectParameters>
                <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
                    PropertyName="SelectedValue" Type="Int32" />
            </SelectParameters>
        </asp:ObjectDataSource>
    </p>
</asp:Panel>

Para concluir este exercício, precisamos definir a propriedade GridView SelectedIndex como e SelectedSuppliersIndex a ProductsBySupplierPanel propriedade Do Visible Painel como True quando o ListProducts botão é clicado. Para fazer isso, crie um manipulador de eventos para o ListProducts evento button Web control e Click adicione o seguinte código:

Protected Sub ListProducts_Click(sender As Object, e As EventArgs) _
    Handles ListProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
        ProductsBySupplierPanel.Visible = False
    Else
        ' Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex
        ' Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = True
    End If
End Sub

Se um fornecedor não tiver sido selecionado no GridView, o ChooseSupplierMsg Rótulo será exibido e o ProductsBySupplierPanel Painel ficará oculto. Caso contrário, se um fornecedor tiver sido selecionado, o ProductsBySupplierPanel será exibido e a propriedade GridView será SelectedIndex atualizada.

A Figura 20 mostra os resultados depois que o fornecedor das Cervejarias Bigfoot foi selecionado e o botão Mostrar Produtos na Página foi clicado.

Os produtos fornecidos pelas cervejarias Bigfoot estão listados na mesma página

Figura 20: Os produtos fornecidos pelas cervejarias Bigfoot estão listados na mesma página (clique para exibir a imagem em tamanho real)

Resumo

Conforme discutido no mestre/detalhe Usando um Selectable Master GridView com um tutorial Details DetailView , os registros podem ser selecionados em um GridView usando um CommandField cuja ShowSelectButton propriedade está definida como True. Mas o CommandField exibe seus botões como botões de push regulares, links ou imagens. Uma interface de usuário de seleção de linha alternativa é fornecer um botão de opção ou uma caixa de seleção em cada linha gridView. Neste tutorial, examinamos como adicionar uma coluna de botões de opção.

Infelizmente, adicionar uma coluna de botões de opção não é tão simples ou simples quanto se poderia esperar. Não há nenhum RadioButtonField interno que possa ser adicionado ao clicar em um botão e usar o controle Web RadioButton em um TemplateField apresenta seu próprio conjunto de problemas. No final, para fornecer essa interface, precisamos criar uma classe personalizada DataControlField ou recorrer a injetar o HTML apropriado em um TemplateField durante o RowCreated evento.

Tendo explorado como adicionar uma coluna de botões de opção, vamos voltar nossa atenção para adicionar uma coluna de caixas de seleção. Com uma coluna de caixas de seleção, um usuário pode selecionar uma ou mais linhas gridView e, em seguida, executar alguma operação em todas as linhas selecionadas (como selecionar um conjunto de emails de um cliente de email baseado na Web e, em seguida, optar por excluir todos os emails selecionados). No próximo tutorial, veremos como adicionar essa coluna.

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 David Suru. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.