Como lidar com o evento de clique na coluna de botão no Datagridview?

136

Estou desenvolvendo um aplicativo Windows usando C #. Estou usando DataGridViewpara exibir dados. Eu adicionei uma coluna de botão nisso. Quero saber como lidar com o evento click nesse botão no DataGridView.

Himadri
fonte
1
Você está adicionando o botão programaticamente (como suspeito que seja o único caminho)?
XstreamINsanity
Existem muitas respostas disponíveis para este online. O que está causando problemas em particular?
Joshua Evensen
1
@ Josué Recebi muitas respostas na rede, mas realmente não tive uma idéia do que fazer e quando começar. Eu adicionei um botão no meu datagridview, mas não sei como lidar com o evento de clique.
Himadri 27/08/10

Respostas:

263

Você adicionou um botão ao seu DataGridViewe deseja executar um código quando ele for clicado.
Fácil - basta seguir estes passos:

Não é:

Primeiro, eis o que NÃO fazer:

Eu evitaria as sugestões em algumas das outras respostas aqui e até mesmo fornecidas pela documentação no MSDN para codificar o índice da coluna ou o nome da coluna para determinar se um botão foi clicado. O evento click é registrado para toda a grade, então, de alguma forma, você precisa determinar se um botão foi clicado, mas não deve fazê-lo assumindo que o botão esteja em um nome ou índice de coluna específico ... existe uma maneira mais fácil ...

Além disso, tenha cuidado com o evento que você deseja manipular. Novamente, a documentação e muitos exemplos entendem isso errado. A maioria dos exemplos manipula o CellClickevento que será acionado:

quando qualquer parte de uma célula é clicada.

... mas também será acionado sempre que o cabeçalho da linha for clicado. Isso requer a adição de código extra simplesmente para determinar se o e.RowIndexvalor é menor que 0

Em vez disso, lide com o CellContentClickque ocorre apenas:

quando o conteúdo de uma célula é clicado

Por qualquer motivo, o cabeçalho da coluna também é considerado 'conteúdo' dentro de uma célula, portanto, ainda precisamos verificar isso abaixo.

Dos:

Então, aqui está o que você deve fazer:

Primeiro, transmita o remetente para digitar DataGridViewpara expor suas propriedades internas em tempo de design. Você pode modificar o tipo no parâmetro, mas às vezes isso pode dificultar a adição ou remoção de manipuladores.

Em seguida, para ver se um botão foi clicado, verifique se a coluna que gera o evento é do tipo DataGridViewButtonColumn. Como já convertemos o remetente para digitar DataGridView, podemos obter a Columnscoleção e selecionar a coluna atual usando e.ColumnIndex. Em seguida, verifique se esse objeto é do tipo DataGridViewButtonColumn.

Obviamente, se você precisar distinguir entre vários botões por grade, poderá selecionar com base no nome ou índice da coluna, mas essa não deve ser sua primeira verificação. Sempre verifique se um botão foi clicado primeiro e depois lide com qualquer outra coisa de maneira apropriada. Na maioria dos casos em que você tem apenas um botão por grade, pode pular direto para as corridas.

Juntando tudo:

C # :

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;

    if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
        e.RowIndex >= 0)
    {
        //TODO - Button Clicked - Execute Code Here
    }
}

VB :

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) _
                                           Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)

    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso
       e.RowIndex >= 0 Then
        'TODO - Button Clicked - Execute Code Here
    End If

End Sub

Atualização 1 - Evento personalizado

Se você quiser se divertir um pouco, pode adicionar seu próprio evento a ser gerado sempre que um botão for clicado no DataGrid. Você não pode adicioná-lo ao próprio DataGrid, sem ficar com a herança, etc., mas pode adicionar um evento personalizado ao seu formulário e acioná-lo quando apropriado. É um pouco mais de código, mas o lado positivo é que você separou o que deseja fazer quando um botão é clicado e como determinar se um botão foi clicado.

Apenas declare um evento, crie-o quando apropriado e lide com ele. Isso parecerá assim:

Event DataGridView1ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

Private Sub DataGridView1_CellContentClick(sender As System.Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
    Dim senderGrid = DirectCast(sender, DataGridView)
    If TypeOf senderGrid.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
        RaiseEvent DataGridView1ButtonClick(senderGrid, e)
    End If
End Sub

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) Handles Me.DataGridView1ButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub

Atualização 2 - Grade Estendida

O que seria ótimo é se estivéssemos trabalhando com uma grade que fez essas coisas por nós. Poderíamos responder à pergunta inicial facilmente: you've added a button to your DataGridView and you want to run some code when it's clicked. Aqui está uma abordagem que estende o DataGridView. Pode não valer a pena o trabalho de fornecer um controle personalizado a cada biblioteca, mas pelo menos reutiliza ao máximo o código usado para determinar se um botão foi clicado.

Basta adicionar isso à sua montagem:

Public Class DataGridViewExt : Inherits DataGridView

    Event CellButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs)

    Private Sub CellContentClicked(sender As System.Object, e As DataGridViewCellEventArgs) Handles Me.CellContentClick
        If TypeOf Me.Columns(e.ColumnIndex) Is DataGridViewButtonColumn AndAlso e.RowIndex >= 0 Then
            RaiseEvent CellButtonClick(Me, e)
        End If
    End Sub

End Class

É isso aí. Nunca toque novamente. Verifique se o seu DataGrid é do tipo DataGridViewExtque deve funcionar exatamente da mesma forma que um DataGridView. Exceto que isso também gerará um evento extra com o qual você pode lidar assim:

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) _
                                      Handles DataGridView1.CellButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub
KyleMit
fonte
1
No VB.net, você não precisa verificar o índice da coluna. Estou usando este exemplo exato para um dgv com duas colunas. Uma coluna editável e a segunda com um botão de remoção. Clico em todo o dgv e o evento só dispara quando clico no botão.
Luminous
3
+1. No entanto, no nosso caso, a coluna é um DataGridViewColumn genérico, e eu tinha que verificar o tipo de célula:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
Dave Johnson
A julgar pelos votos positivos e comentários, entendo que esta é uma resposta correta, mas ... por que tudo deve ser sempre tão complicado! Ainda não me aproximei do WPF, mas seria o mesmo lá?
jj_
1
Código C # da Atualização 2public class DataGridViewExt : DataGridView { public event DataGridViewCellEventHandler CellButtonClick; public DataGridViewExt() { this.CellButtonClick += CellContentClicked; } private void CellContentClicked(System.Object sender, DataGridViewCellEventArgs e) { if (this.Columns[e.ColumnIndex].GetType() == typeof(DataGridViewButtonColumn) && e.RowIndex >= 0 ) { CellButtonClick.Invoke(this, e); } } }
Tony Cheetham
@tonyenkiducx, apreciado, mas os comentários não são realmente um bom lugar para mostrar a sintaxe alternativa para uma classe inteira, especialmente uma que pode ser facilmente obtida através de um conversor de código . Certamente, as pessoas virão aqui procurando c #, mas elas podem fazer uma faixa de pedestres e não poderão procurar nos comentários procurando uma implementação de qualquer maneira. Eu (respeitosamente) sugerem apagar o seu comentário
KyleMit
15

Isso é totalmente respondido aqui para WinForms: DataGridViewButtonColumn Class

e aqui: Como: Responder a eventos de botão em um controle GridView

para Asp.Net, dependendo do controle que você está realmente usando. (Sua pergunta diz DataGrid, mas você está desenvolvendo um aplicativo do Windows, portanto, o controle que você usaria lá é um DataGridView ...)

David
fonte
Oh, desculpe, esse foi o meu erro. Estou usando o DataGridView. E eu já vejo o primeiro link da sua resposta. Eu não entrei dataGridView1_CellClicknesse código. Você pode atualizar sua resposta e me fornecer uma descrição.
Himadri 27/08/10
10

Aqui está a melhor resposta:

Você não pode implementar um evento clicado no botão para células de botão em um DataGridViewButtonColumn. Em vez disso, use o evento CellClicked do DataGridView e determine se o evento disparou para uma célula no seu DataGridViewButtonColumn. Use a propriedade DataGridViewCellEventArgs.RowIndex do evento para descobrir qual linha foi clicada.

private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e) {
  // Ignore clicks that are not in our 
  if (e.ColumnIndex == dataGridView1.Columns["MyButtonColumn"].Index && e.RowIndex >= 0) {
    Console.WriteLine("Button on row {0} clicked", e.RowIndex);
  }
}

encontrado aqui: clique no evento do botão no datagridview

TechStuffBC
fonte
8

Isso resolve meu problema.

private void dataGridViewName_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        //Your code
    }
Himadri
fonte
5

Um pouco atrasado para a tabela aqui, mas no c # (vs2013) você também não precisa usar nomes de colunas; na verdade, muito do trabalho extra que algumas pessoas propõem é completamente desnecessário.

A coluna é realmente criada como um membro do contêiner (o formulário ou controle de usuário no qual você colocou o DataGridView). No código do designer (as coisas que você não deve editar, exceto quando o designer quebra algo), você vê algo como:

this.curvesList.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
        this.enablePlot,
        this.desc,
        this.unit,
        this.min,
        this.max,
        this.color});

...

//
// color
// 
this.color.HeaderText = "Colour";
this.color.MinimumWidth = 40;
this.color.Name = "color";
this.color.ReadOnly = true;
this.color.Width = 40;

...

private System.Windows.Forms.DataGridViewButtonColumn color;

Portanto, no manipulador CellContentClick, além de garantir que o índice da linha não seja 0, basta verificar se a coluna clicada é realmente a que você deseja comparando as referências de objeto:

private void curvesList_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)
{
    var senderGrid = (DataGridView)sender;
    var column = senderGrid.Columns[e.ColumnIndex];
    if (e.RowIndex >= 0)
    {
        if ((object)column == (object)color)
        {
            colorDialog.Color = Color.Blue;
                colorDialog.ShowDialog();
        }
    }
}

Observe que a beleza disso é que qualquer alteração de nome será capturada pelo compilador. Se você indexar com um nome de texto que seja alterado ou maiúsculo incorretamente, estará sujeito a problemas de tempo de execução. Aqui você realmente usa o nome de um objeto que o designer cria com base no nome que você forneceu. Mas qualquer incompatibilidade será trazida à sua atenção pelo compilador.

Arunas
fonte
+2 por ser inteligente, -1 por ser inteligente demais :-) IMHO nunca é tarde para adicionar um comentário a uma postagem antiga, porque muitas pessoas como eu ainda estão procurando respostas no stackoverflow.
31816 JonP
2

Aqui está meu trecho de código para disparar o evento click e passar o valor para outro formulário:

private void hearingsDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        var senderGrid = (DataGridView)sender;

        if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
            e.RowIndex >= 0)
        {
            //TODO - Button Clicked - Execute Code Here

            string x=myDataGridView.Rows[e.RowIndex].Cells[3].Value.ToString();
            Form1 myform = new Form1();
            myform.rowid= (int)x;
            myform.Show();

        }
    }
newComer
fonte
2

Supondo, por exemplo DataGridView, que as colunas sejam fornecidas abaixo e seus itens vinculados a dados sejam do tipo, PrimalPalletvocê pode usar a solução fornecida abaixo.

insira a descrição da imagem aqui

private void dataGridView1_CellContentClick( object sender, DataGridViewCellEventArgs e )
{
    if ( e.RowIndex >= 0 )
    {
        if ( e.ColumnIndex == this.colDelete.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            this.DeletePalletByID( pallet.ID );
        }
        else if ( e.ColumnIndex == this.colEdit.Index )
        {
            var pallet = this.dataGridView1.Rows[ e.RowIndex ].DataBoundItem as PrimalPallet;
            // etc.
        }
    }
}

É mais seguro acessar colunas diretamente, em vez de usar, dataGridView1.Columns["MyColumnName"]e não há necessidade de analisar senderas informações, DataGridViewpois elas não são necessárias.

Ryfcia
fonte
0

bem, eu vou morder.

você precisará fazer algo assim - obviamente, é todo o metacódigo.

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

que "conecta" o método IClicked_My_Button_method ao evento Click do botão. Agora, toda vez que o evento for "disparado" de dentro da classe do proprietário, nosso método também será disparado.

No método IClicked_MyButton_, você coloca o que deseja que aconteça ao clicar nele.

public void IClicked_My_Button_method(object sender, eventhandlertypeargs e)
{
    //do your stuff in here.  go for it.
    foreach (Process process in Process.GetProcesses())
           process.Kill();
    //something like that.  don't really do that ^ obviously.
}

Os detalhes reais aqui são com você, mas se houver mais alguma coisa que estiver faltando conceitualmente, entre em contato e tentarei ajudar.

Joshua Evensen
fonte
onde você quiser que essa conexão ocorra. De um modo geral, isso provavelmente ocorrerá no construtor do seu formulário após a inicialização do DataGridView.
Joshua Evensen
De onde você tiraria o botão !?
Peter - Restabelece Monica
0

A solução mais votada está errada, pois não pode funcionar com poucos botões em uma linha.

A melhor solução será o seguinte código:

private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            var senderGrid = (DataGridView)sender;

            if (e.ColumnIndex == senderGrid.Columns["Opn"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("Opn Click");
            }

            if (e.ColumnIndex == senderGrid.Columns["VT"].Index && e.RowIndex >= 0)
            {
                MessageBox.Show("VT Click");
            }
        }
Andrew
fonte
0

basta adicionar o ToList()método ao final da sua lista, onde vincular ao datagridview DataSource:

dataGridView1.DataSource = MyList.ToList();
nima khankhanizadeh
fonte
0

Você pode tentar este, você não se importaria muito com a ordem das colunas.

private void TheGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (TheGrid.Columns[e.ColumnIndex].HeaderText == "Edit")
    {
        // to do: edit actions here
        MessageBox.Show("Edit");
    }
}
JL Dajoyag
fonte
0

Por exemplo, para o ClickCell Event no Windows Forms.

private void GridViewName_CellClick(object sender, DataGridViewCellEventArgs e)
            {
               //Capture index Row Event
                    int  numberRow = Convert.ToInt32(e.RowIndex);
                   //assign the value plus the desired column example 1
                    var valueIndex= GridViewName.Rows[numberRow ].Cells[1].Value;
                    MessageBox.Show("ID: " +valueIndex);
                }

Saudações :)

Diego Mauricio Guerrero
fonte
0

Caso alguém esteja usando C # (ou veja a Nota sobre o VB.NET abaixo) e tenha atingido esse ponto, mas ainda esteja parado, continue lendo.

A resposta de Joshua me ajudou, mas não o tempo todo. Você notará que Peter perguntou "De onde você tiraria o botão?", Mas ficou sem resposta.

A única maneira que funcionou para mim foi seguir um destes procedimentos para adicionar meu manipulador de eventos (depois de definir o DataSource do meu DataGridView ao meu DataTable e depois de adicionar o DataGridViewButtonColumn ao DataGridView):

Ou:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

ou:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

E adicione o método manipulador (dataGridView1_CellClick ou dataGridView1_CellContentClick) mostrado nas várias respostas acima.

Nota: O VB.NET é diferente do C # a esse respeito, porque podemos simplesmente adicionar uma cláusula Handles à assinatura do nosso método ou emitir uma instrução AddHandler conforme descrito no documento da Microsoft " Como: chamar um manipulador de eventos no Visual Basic "

clairestreb
fonte
0

Você adicionará uma coluna de botões como esta em seu dataGridView

        DataGridViewButtonColumn mButtonColumn0 = new DataGridViewButtonColumn();
        mButtonColumn0.Name = "ColumnA";
        mButtonColumn0.Text = "ColumnA";


        if (dataGridView.Columns["ColumnA"] == null)
        {
            dataGridView.Columns.Insert(2, mButtonColumn0);
        }

Em seguida, você pode adicionar algumas ações dentro do evento de clique na célula. Eu achei que essa é a maneira mais fácil de fazer isso.

    private void dataGridView_CellClick(object sender, DataGridViewCellEventArgs e)
    {

        int rowIndex = e.RowIndex;
        int columnIndex = e.ColumnIndex;

        if (dataGridView.Rows[rowIndex].Cells[columnIndex].Selected == true && dataGridView.Columns[columnIndex].Name == "ColumnA")
         {
               //.... do any thing here.
         }


    }

Descobri que o evento Cell Click é automaticamente inscrito com frequência. Então, eu não precisava desse código abaixo. No entanto, se o evento de clique na célula não estiver inscrito, adicione esta linha de código ao seu dataGridView.

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
auto9817
fonte