Partilhar via


Adicionando uma coluna GridView de botões de rádio (VB)

por Scott Mitchell

Descarregar PDF

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

Introdução

O controle GridView oferece uma grande quantidade de funcionalidade integrada. Ele inclui vários campos diferentes para exibir texto, imagens, hiperlinks e botões. Ele suporta modelos para personalização adicional. Com alguns cliques do mouse, é possível fazer um GridView onde cada linha pode ser selecionada através de um botão, ou para ativar recursos de edição ou exclusão. Apesar da infinidade de recursos fornecidos, muitas vezes haverá situações em que recursos adicionais e não suportados 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 linhas. Como examinado no Master/Detail usando uma GridView principal selecionável com uma DetailView, podemos adicionar um CommandField ao GridView que inclui um botão de seleção. Ao clicar, um postback ocorre e a propriedade SelectedIndex do GridView é atualizada para o índice da linha cujo botão de Selecionar foi clicado. No tutorial Master/Detail Using a Selectable Master GridView with a Details DetailView , vimos como usar esse recurso para exibir detalhes para a linha GridView selecionada.

Embora o botão Selecionar funcione em muitas situações, ele pode não funcionar tão bem para outras. Alternativamente a usar um botão, outros dois 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 uma caixa de seleção. Em cenários em que o utilizador só pode selecionar um dos registos do GridView, o botão de opção pode ser preferido ao botão Selecionar. Em situações em que o usuário pode selecionar vários registros, como em um aplicativo de email baseado na Web, onde 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 de usuário do botão Selecionar ou do botão de opção.

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

Etapa 1: Criando e aprimorando as páginas da Web do GridView

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

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

Adicionar páginas ASP.NET para os Tutoriais SqlDataSource-Related

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

Como nas outras pastas, Default.aspx na EnhancedGridView pasta irá listar os tutoriais em sua seção. Lembre-se de que o SectionLevelTutorialListing.ascx Controle de Usuário fornece essa funcionalidade. Portanto, adicione este Controlo do Utilizador a Default.aspx arrastando-o do Gerenciador de Soluções para a vista de Design da página.

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

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

Por último, adicione estas quatro páginas como entradas ao Web.sitemap ficheiro. Especificamente, adicione a seguinte marcação depois de usar o controlo SqlDataSource <siteMapNode>:

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

Após a atualização Web.sitemap, reserve um momento para visualizar o site de tutoriais através 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 os tutoriais Aprimorando o GridView

Figura 3: O mapa do site agora inclui entradas para os tutoriais Aprimorando o GridView

Etapa 2: Exibindo os fornecedores em um GridView

Para este tutorial, vamos criar um GridView que lista os fornecedores dos Estados Unidos, em que cada linha do GridView oferece um botão de opção. Depois de selecionar um fornecedor através do botão de opção, o utilizador pode visualizar os produtos do fornecedor clicando num botão. Embora essa tarefa possa parecer 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 por abrir a página RadioButtonField.aspx na pasta EnhancedGridView ao arrastar um GridView da Caixa de Ferramentas para o Designer. Defina o GridView s ID como Suppliers e, a partir de sua marca inteligente, escolha criar uma nova fonte de dados. Especificamente, crie um ObjectDataSource chamado SuppliersDataSource que extrai seus dados do SuppliersBLL objeto.

Criar um novo ObjectDataSource chamado SuppliersDataSource

Figura 4: Criar um novo ObjectDataSource nomeado SuppliersDataSource (Clique para visualizar a imagem em tamanho real)

Captura de tela da janela Configurar Fonte de Dados - FornecedoresDataSource com o menu suspenso do objeto de negócios aberto. FornecedoresBLL é selecionado e o botão Avançar é realçado.

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

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

Captura de ecrã da janela Configurar Fonte de Dados - FornecedoresDataSource no separador SELECT com o menu suspenso do método aberto. A opção de método GetSupplierByCountry está selecionada e o botão Seguinte está realçado.

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

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

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

Figura 7: Configurar o ObjectDataSource para usar a classe (SuppliersBLL 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 pré-definido (EUA, neste exemplo), deixe a lista suspensa de origem do parâmetro definida como Nenhum e insira o valor padrão no campo de texto. Clique em Concluir para finalizar o assistente.

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

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

Depois de concluir o assistente, o GridView incluirá um BoundField para cada um dos campos de dados de fornecedores. Remova todos, exceto o CompanyName, City, e Country BoundFields, e renomeie a propriedade CompanyNameHeaderText para Fornecedor. 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, permite que o usuário visualize os produtos de fornecedores selecionados na mesma página que a lista de fornecedores ou em uma página diferente. Para acomodar isso, adicione dois controles da Web Button à página. Eu defini os ID desses dois botões para ListProducts e SendToProducts, com a ideia de que quando ListProducts for clicado ocorrerá um postback e os produtos do fornecedor selecionado serão listados na mesma página, mas quando SendToProducts for clicado, o usuário será levado para uma outra página que lista os produtos.

A Figura 9 mostra os Suppliers controles GridView e Button Web quando visualizados 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 visualizar a imagem em tamanho real)

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

Neste ponto, o Suppliers GridView tem três BoundFields exibindo o nome da empresa, cidade e 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 integrado; caso contrário, poderíamos simplesmente adicionar isso à grelha e estar concluído. Em vez disso, podemos adicionar um TemplateField e configurá-lo ItemTemplate para renderizar um botão de opção, resultando num botão de opção para cada linha do GridView.

Inicialmente, podemos supor que a interface de usuário desejada pode 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 entre si e, portanto, não são mutuamente exclusivos. Ou seja, um usuário final é capaz de selecionar vários botões de opção simultaneamente a partir do GridView.

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

Adicionar um controle da Web RadioButton ao ItemTemplate

Figura 10: Adicione um controlo Web RadioButton ao ItemTemplate (Clique para visualizar 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 RadioButtons GroupName é utilizada para agrupar uma série de botões de opção. Todos os controles RadioButton com o mesmo GroupName valor são considerados agrupados, apenas um botão de opção pode ser selecionado de um grupo de cada vez. A propriedade GroupName especifica o valor para o atributo name do botão de rádio renderizado. O navegador examina os atributos dos botões name de opção para determinar os agrupamentos de botões de opção.

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

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

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

A razão porque os botões de opção não são agrupados é porque os seus atributos renderizados name são diferentes, apesar de terem a mesma definição de propriedade GroupName. Para ver essas diferenças, faça uma Visualizar/Código-Fonte no navegador e examine a marcação do botão rádio:

<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 tanto os atributos name quanto id não são os valores exatos conforme especificado na Janela de Propriedades, mas são precedidos por diversos outros valores ID. Os valores adicionais ID adicionados à frente dos atributos renderizados id e name são os ID dos botões de opção dos controlos-pai de GridViewRow, de ID, do GridView ID, do control de Conteúdo ID e do Web Form ID. Esses ID s são adicionados para que cada controle da Web renderizado no GridView tenha valores id e name exclusivos.

Cada control renderizado precisa de um identificador diferente, como name e id, porque é assim que o navegador identifica exclusivamente cada control na parte cliente e como comunica ao servidor web qual ação ou alteração ocorreu durante o postback. Por exemplo, imagine que queríamos executar algum código do lado do servidor sempre que o estado verificado de um RadioButton fosse alterado. Poderíamos fazer isso definindo a propriedade RadioButton s AutoPostBack como True e criando um manipulador de eventos para o CheckChanged evento. No entanto, se os valores renderizados de name e id para todos os botões de rádio fossem os mesmos, no postback, não poderíamos determinar qual botão de rádio específico foi clicado.

O resumo disso é que não podemos criar uma coluna de botões de rádio em um GridView usando o controlo Web RadioButton. Em vez disso, devemos usar técnicas bastante arcaicas para garantir que a marcação apropriada seja injetada em cada linha do GridView.

Observação

Como o controlo Web RadioButton, o controlo HTML do rádio, quando adicionado a um modelo, incluirá o atributo exclusivo name, tornando os botões de rádio na grelha não agrupados. Se você não estiver familiarizado com controles HTML, sinta-se à vontade para ignorar esta nota, pois os controles HTML raramente são usados, especialmente no ASP.NET 2.0. Mas se você estiver interessado em saber mais, consulte a entrada do blog de K. Scott Allen Web Controls and HTML Controls.

Uso de um Literal Control para inserir marcação de botão de rádio

Para agrupar corretamente todos os botões de opção dentro do GridView, é necessário inserir manualmente o código de marcação dos botões de opção no ItemTemplate. Cada botão de opção precisa do mesmo atributo name, mas deve ter um atributo exclusivo id (caso desejemos aceder a um botão de opção via script no lado do cliente). Depois que um usuário seleciona um botão de opção e recarrega a página, o navegador enviará de volta o valor do atributo s value do botão de opção selecionado. Portanto, cada botão de opção precisará de um atributo value exclusivo. Finalmente, no postback, precisamos assegurar-nos de adicionar o atributo checked ao botão de opção selecionado; caso contrário, depois que o usuário fizer uma seleção e efetuar um postback, os botões de opção retornarão ao seu estado padrão (todos desmarcados).

Há duas abordagens que podem ser adotadas para injetar marcação de baixo nível em um modelo. Uma delas é fazer uma mistura 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 . No nosso caso, pode ser algo como:

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

Aqui, GetUniqueRadioButton e GetRadioButtonValue seriam métodos definidos na classe code-behind que retornassem os atributos id e value com os valores apropriados para cada botão de opção. Essa abordagem funciona bem para atribuir os id atributos e value , mas fica aquém quando é necessário especificar o valor do checked atributo porque a sintaxe de vinculação de dados só é executada quando os dados são vinculados 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 redirecionado 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 deixar nisso. No entanto, gostaria de o encorajar a tentar usar a abordagem acima e desenvolvê-la até ao ponto em que ficará bloqueado. 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 RowCreated ou RowDataBound do GridView, o controle Literal pode ser acessado programaticamente, e sua propriedade Text definida para emitir a marcação.

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 Literal Control ao ItemTemplate (Clique para ver a imagem em tamanho real)

Em seguida, crie um manipulador de eventos para o evento s GridView RowCreated . O RowCreated evento é acionado uma vez para cada linha adicionada, independentemente de os dados estarem ou não sendo reencaminhados para o GridView. Isso significa que, mesmo em um postback quando os dados são recarregados do estado de exibição, o evento RowCreated ainda é acionado e essa é a razão pela qual estamos a utilizá-lo em vez de RowDataBound (que é acionado apenas quando os dados estão explicitamente vinculados ao controlo Web de dados).

Neste manipulador de eventos, só queremos continuar se estivermos lidando com uma linha de dados. Para cada linha de dados, pretendemos referenciar o controle RadioButtonMarkup Literal de forma programada e definir a sua propriedade Text para 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 atributo name é definido como SuppliersGroup, cujo atributo id é definido como RowSelectorX, onde X é o índice da linha GridView, e cujo atributo value é 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 fornecedor selecionado. Portanto, pode-se pensar que o valor de cada botão de opção deve ser o verdadeiro valor 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 impede um usuário travesso de manipular o valor SupplierID enviado de volta no postback? Usando o índice de linha como o value, e, em seguida, obtendo o SupplierID no postback da coleção DataKeys, podemos garantir que o usuário esteja usando apenas um dos SupplierID valores associados a uma das linhas do 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 grelha pode ser selecionado de cada vez. No entanto, ao selecionar um botão de rádio e clicar num dos botões, ocorre um postback e todos os botões de rádio retornam ao seu estado inicial (ou seja, no postback, o botão de rádio selecionado não é mais selecionado). Para corrigir isso, precisamos modificar o RowCreated manipulador de eventos para que ele inspecione o índice do botão de rádio selecionado enviado do postback e adicione o atributo checked="checked" à marcação emitida quando o índice da linha corresponder.

Quando ocorre um postback, o navegador reenvia os name e value do botão de opção selecionado. O valor pode ser recuperado programaticamente usando Request.Form("name"). A Request.Form propriedade fornece uma representação das NameValueCollection variáveis do 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 ocorre um postback. Como o atributo renderizado name dos botões de opção no GridView é SuppliersGroup, quando a página da Web é submetida novamente, o navegador enviará SuppliersGroup=valueOfSelectedRadioButton de volta para o servidor da Web (junto com os outros campos de formulário). Essas informações podem ser acessadas a partir da Request.Form propriedade usando: Request.Form("SuppliersGroup").

Como precisaremos determinar o índice de 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 esta propriedade adicionada, sabemos que devemos adicionar a marcação checked="checked" no manipulador de eventos RowCreated quando SuppliersSelectedIndex for igual a e.Row.RowIndex. Atualize o manipulador de eventos para incluir esta 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 esta alteração, o botão de opção selecionado permanece selecionado após um evento de 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 for visitada pela primeira vez, o botão de opção da primeira linha do GridView seja 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, adicionámos uma coluna de botões de rádio agrupados ao GridView que permite que uma única linha do GridView seja selecionada e lembrada em reenvios de página. Nossos próximos passos são exibir os produtos fornecidos pelo fornecedor selecionado. Na Etapa 4, veremos como redirecionar o utilizador para outra página, enviando junto com o item 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 derivam os campos BoundField, CheckBoxField, TemplateField e outros campos internos GridView e DetailsView. Criar uma classe personalizada DataControlField significaria que a coluna de botões de rádio poderia ser adicionada apenas usando sintaxe declarativa, e também facilitaria significativamente a reprodução da funcionalidade em outras páginas web e outras aplicações web.

Se você já criou controles personalizados e compilados em ASP.NET, sabe que fazer isso requer uma boa quantidade de trabalho preliminar e envolve uma série de sutilezas e casos excepcionais que devem ser cuidadosamente tratados. Portanto, vamos renunciar a implementar uma coluna de botões de opção como uma classe personalizada DataControlField por enquanto e manter 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 seleciona uma linha GridView, precisamos mostrar os produtos do fornecedor selecionado. Em algumas circunstâncias, podemos querer exibir esses produtos em uma página separada, em outras podemos preferir fazê-lo na mesma página. Vamos primeiro examinar como exibir os produtos em uma página separada; na Etapa 5, veremos como adicionar um GridView para RadioButtonField.aspx exibir os produtos do fornecedor selecionado.

Atualmente, existem dois controles Button Web 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 Master/Detail Filtering Across Two Pages e exibe os produtos do fornecedor cujo SupplierID é passado através do campo de string de consulta chamado SupplierID.

Para fornecer essa funcionalidade, crie um manipulador de eventos para o SendToProducts evento Button s Click . Na Etapa 3, adicionámos a propriedade SuppliersSelectedIndex, que retorna o índice da linha cujo botão de rádio está selecionado. O correspondente SupplierID pode ser recuperado da coleção DataKeys do GridView e o usuário pode então 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

Este código funciona maravilhosamente, desde que se selecione um dos botões de opção no GridView. Se, inicialmente, o GridView não tiver nenhum botão de opção selecionado e o utilizador clicar no botão SendToProducts, SuppliersSelectedIndex será -1, o que fará com que uma exceção seja lançada, uma vez que -1 está fora do intervalo dos índices da coleção DataKeys. Todavia, isto não é um problema, caso tenha decidido atualizar o RowCreated manipulador de eventos conforme discutido na Etapa 3, de modo a ter o primeiro botão de rádio no GridView inicialmente selecionado.

Para acomodar um valor de SuppliersSelectedIndex, adicione um controlo Web de Etiqueta à página acima do -1GridView. Defina a sua ID propriedade como ChooseSupplierMsg, a sua CssClass propriedade para Warning, as suas EnableViewState e Visible propriedades para False, e a sua Text propriedade para Escolha um fornecedor na grelha. A classe Warning CSS exibe texto em uma fonte vermelha, itálica, negrito e grande e é definida em Styles.css. Ao definir as propriedades EnableViewState e Visible como False, o Label não é renderizado, exceto apenas para os postbacks em que a propriedade Visible do controle é programaticamente definida como True.

Adicionar o controle web de etiqueta acima do GridView

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

Em seguida, modifique o Click manipulador de eventos para exibir o ChooseSupplierMsg Label se SuppliersSelectedIndex for menor que zero e redirecione o usuário para ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID, caso 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 SendToProducts no 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. Isto irá levá-lo a uma página que lista os produtos fornecidos pelo fornecedor selecionado. A Figura 15 mostra a ProductsForSupplierDetails.aspx página em que o fornecedor da Bigfoot Breweries foi selecionado.

A etiqueta ChooseSupplierMsg é exibida se nenhum fornecedor for selecionado

Figura 14: O ChooseSupplierMsg rótulo é exibido se nenhum fornecedor for selecionado (Clique para visualizar 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 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. Alternativamente, 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 for selecionado, adicione um controle Web Panel abaixo do Suppliers GridView, definindo seu ID 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 etiqueta inteligente de GridView, escolha ligá-la a um novo ObjectDataSource chamado ProductsBySupplierDataSource.

Associar o ProductsBySupplier GridView a um novo ObjectDataSource

Figura 16: Vincular o GridView a um novo ObjectDataSource (Clique para visualizar a ProductsBySupplierimagem em tamanho real)

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

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

Figura 17: Configurar o ObjectDataSource para usar o método (GetProductsBySupplierID(supplierID) imagem em tamanho real)

Defina as listas de Drop-Down como (Nenhum) nas guias UPDATE, INSERT e DELETE

Figura 18: Defina as listas de Drop-Down como (Nenhum) nas guias UPDATE, INSERT e DELETE (Clique para visualizar a imagem em tamanho real)

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

Temos algumas opções aqui para especificar a origem do valor do parâmetro. Podemos usar o objeto Parameter padrão e, de forma programática, atribuir o valor da propriedade SuppliersSelectedIndex à propriedade DefaultValue do Parameter no evento Selecting do manipulador de eventos do ObjectDataSource. Consulte novamente o tutorial Programmatically Setting the ObjectDataSource's Parameter Values para obter uma atualização sobre a atribuição programática de valores aos parâmetros de ObjectDataSource.

Como alternativa, podemos usar um ControlParameter e fazer referência à Suppliers propriedade do GridView SelectedValue (consulte a Figura 19). A propriedade GridView s SelectedValue retorna o DataKey valor correspondente à SelectedIndex propriedade. Para que esta opção funcione, precisamos definir programaticamente a propriedade SelectedIndex do GridView para a linha selecionada quando o botão ListProducts for clicado. Como um benefício adicional, ao definir o SelectedIndex, o registro selecionado assumirá o SelectedRowStyle definido no DataWebControls Tema (um fundo amarelo).

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

Figura 19: Use um ControlParameter para especificar o valor selecionado no GridView como a fonte do parâmetro (Clique para visualizar 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 os CamposLimitados ProductName, CategoryName e UnitPrice, e altere as propriedades HeaderText para Produto, Categoria e Preço. 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 ter a seguinte aparência:

<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 SelectedIndex do GridView para a SelectedSuppliersIndex e a propriedade ProductsBySupplierPanel do Visible Panel para True quando o botão ListProducts for clicado. Para fazer isso, crie um manipulador de eventos para o ListProducts evento Button Web control s Click e 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 oculto. Caso contrário, se um fornecedor tiver sido selecionado, o ProductsBySupplierPanel será exibido e a propriedade GridView s SelectedIndex será atualizada.

A Figura 20 mostra os resultados depois que o fornecedor da Bigfoot Breweries foi selecionado e o botão Mostrar produtos na página foi clicado.

Os produtos fornecidos pela Bigfoot Breweries estão listados na mesma página

Figura 20: Os produtos fornecidos pela Bigfoot Breweries estão listados na mesma página (Clique para visualizar a imagem em tamanho real)

Resumo

Conforme discutido no tutorial Master/Detail Using a Selectable Master GridView with a Details DetailView, os registos podem ser selecionados de um GridView usando um CommandField cuja propriedade ShowSelectButton está definida como True. Mas o CommandField exibe seus botões como botões regulares, links ou imagens. Uma interface de utilizador alternativa para seleção de linha é fornecer um botão de opção ou caixa de seleção em cada linha do 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 fácil ou direto quanto se poderia esperar. Não há RadioButtonField interno que possa ser adicionado com o clique de um botão, e usar o controle RadioButton Web dentro de um TemplateField introduz seu próprio conjunto de problemas. No final, para fornecer tal interface, temos que 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 agora concentrar nossa atenção em como 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 e-mails de um cliente de e-mail baseado na Web e, em seguida, optar por excluir todos os e-mails selecionados). No próximo tutorial, veremos como adicionar essa coluna.

Feliz Programação!

Sobre o Autor

Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.

Um agradecimento especial a

Esta série de tutoriais foi revisada por muitos revisores úteis. O revisor principal deste tutorial foi David Suru. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.