Jak obsłużyć zdarzenie kliknięcia w kolumnie przycisków w Datagridview?

136

Zajmuję się tworzeniem aplikacji dla systemu Windows w języku C #. ja używamDataGridView do wyświetlania danych. Dodałem w tym kolumnę z przyciskami. Chcę wiedzieć, jak obsłużyć zdarzenie kliknięcia tego przycisku w DataGridView.

Himadri
źródło
1
Czy dodajesz przycisk programowo (jak podejrzewam, jest to jedyny sposób)?
XstreamINsanity
W Internecie dostępnych jest wiele odpowiedzi na to pytanie. Co w szczególności sprawia ci kłopoty?
Joshua Evensen
1
@Joshua Otrzymałem wiele odpowiedzi w sieci, ale tak naprawdę nie miałem pojęcia, co robić i kiedy zacząć. Dodałem przycisk do mojego datagridview po prostu nie wiem, jak obsłużyć jego zdarzenie kliknięcia.
Himadri

Odpowiedzi:

263

Dodałeś przycisk do swojego DataGridViewi chcesz uruchomić kod po jego kliknięciu.
Łatwe peasy - po prostu wykonaj następujące kroki:

Zakazy:

Po pierwsze, oto czego NIE robić:

Unikałbym sugestii zawartych w niektórych innych odpowiedziach tutaj, a nawet zawartych w dokumentacji MSDN, aby zakodować na stałe indeks kolumny lub nazwę kolumny w celu ustalenia, czy przycisk został kliknięty. Zdarzenie kliknięcia rejestruje całą siatkę, więc musisz w jakiś sposób ustalić, że przycisk został kliknięty, ale nie powinieneś tego robić, zakładając, że przycisk znajduje się w określonej nazwie lub indeksie kolumny ... jest łatwiejszy sposób ...

Uważaj też, które zdarzenie chcesz obsłużyć. Ponownie, dokumentacja i wiele przykładów zawiera błąd. Większość przykładów obsługuje CellClickzdarzenie, które się uruchomi:

po kliknięciu dowolnej części komórki.

... ale będzie również uruchamiany po kliknięciu nagłówka wiersza . Wymaga to dodania dodatkowego kodu, aby po prostu określić, czy e.RowIndexwartość jest mniejsza niż 0

Zamiast tego zajmij się tym, CellContentClickco występuje tylko:

po kliknięciu zawartości w komórce

Z jakiegoś powodu nagłówek kolumny jest również uważany za „zawartość” w komórce, więc nadal będziemy musieli to sprawdzić poniżej.

Dos:

Oto, co powinieneś zrobić:

Najpierw obsadź nadawcę na typ, DataGridViewaby ujawnić jego wewnętrzne właściwości w czasie projektowania. Możesz zmodyfikować typ parametru, ale czasami może to utrudnić dodawanie lub usuwanie programów obsługi.

Następnie, aby zobaczyć, czy przycisk został kliknięty, po prostu sprawdź, czy kolumna podnosząca zdarzenie jest typu DataGridViewButtonColumn. Ponieważ już przerzuciliśmy nadawcę na typ DataGridView, możemy pobrać Columnskolekcję i wybrać bieżącą kolumnę za pomocą e.ColumnIndex. Następnie sprawdź, czy ten obiekt jest typuDataGridViewButtonColumn .

Oczywiście, jeśli chcesz rozróżnić wiele przycisków na siatkę, możesz wybrać na podstawie nazwy kolumny lub indeksu, ale nie powinno to być pierwsze sprawdzenie. Zawsze upewnij się, że najpierw kliknięto przycisk, a następnie odpowiednio obsłuż wszystko inne. W większości przypadków, gdy masz tylko jeden przycisk na siatkę, możesz od razu wskoczyć do wyścigów.

Kładąc wszystko razem:

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

Aktualizacja 1 - wydarzenie niestandardowe

Jeśli chcesz się trochę zabawić, możesz dodać własne zdarzenie, które będzie wywoływane za każdym razem, gdy klikniesz przycisk na DataGrid. Nie możesz dodać go do samego DataGrid bez bałaganu z dziedziczeniem itp., Ale możesz dodać zdarzenie niestandardowe do formularza i uruchomić je w razie potrzeby. To trochę więcej kodu, ale zaletą jest to, że oddzieliłeś, co chcesz zrobić po kliknięciu przycisku, z tym, jak określić, czy przycisk został kliknięty.

Wystarczy zadeklarować zdarzenie, podnieść je w razie potrzeby i obsłużyć. Będzie to wyglądać tak:

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

Aktualizacja 2 - Rozszerzona siatka

Byłoby wspaniale, gdybyśmy pracowali z siatką, która po prostu robi to za nas. Możemy łatwo odpowiedzieć początkowe pytanie: you've added a button to your DataGridView and you want to run some code when it's clicked. Oto podejście, które rozszerza DataGridView. Może nie być warte kłopotów z koniecznością dostarczania niestandardowej kontrolki do każdej biblioteki, ale przynajmniej maksymalnie wykorzystuje ona kod używany do określania, czy przycisk został kliknięty.

Po prostu dodaj to do swojego zespołu:

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

Otóż ​​to. Nigdy więcej tego nie dotykaj. Upewnij się, że DataGrid jest typu, DataGridViewExtktóry powinien działać dokładnie tak samo, jak DataGridView. Z wyjątkiem tego, że spowoduje to również dodatkowe zdarzenie, które możesz obsłużyć w ten sposób:

Private Sub DataGridView1_ButtonClick(sender As DataGridView, e As DataGridViewCellEventArgs) _
                                      Handles DataGridView1.CellButtonClick
    'TODO - Button Clicked - Execute Code Here
End Sub
KyleMit
źródło
1
W VB.net nie musisz sprawdzać indeksu kolumn. Używam tego dokładnego przykładu dla pliku dgv z dwiema kolumnami. Jedna kolumna, którą można edytować, a druga z przyciskiem usuwania. Klikam na całym dgv i zdarzenie jest uruchamiane tylko wtedy, gdy klikam przycisk.
Luminous
3
+1. Jednak w naszym przypadku kolumna jest generyczną kolumną DataGridViewColumn i musiałem sprawdzić typ komórki:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
Dave Johnson
Sądząc po opiniach i komentarzach, rozumiem, że to poprawna odpowiedź, ale ... dlaczego wszystko zawsze musi być takie skomplikowane! Jeszcze nie zbliżyłem się do WPF, ale czy będzie tam tak samo?
jj_
1
Kod C # dla aktualizacji 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, doceniane, ale komentarze nie są tak naprawdę dobrym miejscem do zaprezentowania alternatywnej składni dla całej klasy, zwłaszcza takiej, którą można łatwo uzyskać za pomocą konwertera kodu . Jasne, ludzie będą tu przychodzić, szukając języka C #, ale mogą tam sami przejść dla pieszych i prawdopodobnie i tak nie będą przeglądać komentarzy w poszukiwaniu implementacji. Sugerowałbym (z szacunkiem) usunięcie twojego komentarza
KyleMit,
15

To jest pełne odpowiedzi tutaj dla WinForms: DataGridViewButtonColumn Class

i tutaj: instrukcje: odpowiadanie na zdarzenia przycisków w kontrolce GridView

dla Asp.Net w zależności od kontrolki, której faktycznie używasz. (Twoje pytanie brzmi DataGrid, ale tworzysz aplikację dla systemu Windows, więc kontrolka, której będziesz używać, to DataGridView ...)

David
źródło
Och, przepraszam, to był mój błąd. Używam DataGridView. I już widzę pierwszy link do Twojej odpowiedzi. Nie dostałem się dataGridView1_CellClickdo tego kodu. Czy możesz zaktualizować swoją odpowiedź i podać mi jej opis.
Himadri
10

Oto lepsza odpowiedź:

Nie można zaimplementować zdarzenia kliknięcia przycisku dla komórek przycisku w DataGridViewButtonColumn. Zamiast tego używasz zdarzenia CellClicked DataGridView i określasz, czy zdarzenie zostało uruchomione dla komórki w DataGridViewButtonColumn. Użyj właściwości DataGridViewCellEventArgs.RowIndex zdarzenia, aby dowiedzieć się, który wiersz został kliknięty.

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);
  }
}

znaleziono tutaj: zdarzenie kliknięcia przycisku w datagridview

TechStuffBC
źródło
8

To rozwiązuje mój problem.

private void dataGridViewName_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        //Your code
    }
Himadri
źródło
5

Trochę późno do tabeli tutaj, ale w C # (vs2013) nie musisz też używać nazw kolumn, w rzeczywistości wiele dodatkowej pracy, którą niektórzy proponują, jest całkowicie niepotrzebnych.

Kolumna jest faktycznie tworzona jako element członkowski kontenera (formularz lub kontrolka użytkownika, w której umieściłeś DataGridView). Z kodu projektanta (rzeczy, których nie powinieneś edytować, chyba że projektant coś zepsuje), zobaczysz coś takiego:

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;

Więc w module obsługi CellContentClick, oprócz upewnienia się, że indeks wiersza nie wynosi 0, wystarczy sprawdzić, czy kliknięta kolumna jest faktycznie tą, którą chcesz, porównując odniesienia do obiektów:

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();
        }
    }
}

Zwróć uwagę, że piękno tego polega na tym, że wszelkie zmiany nazw zostaną przechwycone przez kompilator. Jeśli indeksujesz z nazwą tekstową, która się zmienia lub niepoprawnie wpisujesz wielkie litery, jesteś związany z problemami w czasie wykonywania. Tutaj faktycznie używasz nazwy obiektu, który projektant tworzy na podstawie podanej nazwy. Jednak kompilator zwróci uwagę na każdą niezgodność.

Arunas
źródło
+2 za bycie sprytnym, -1 za bycie zbyt sprytnym :-) IMHO Nigdy nie jest za późno, aby dodać komentarz do starego postu, ponieważ wiele osób takich jak ja wciąż szuka odpowiedzi na stackoverflow.
JonP
2

Oto mój fragment kodu uruchamiający zdarzenie kliknięcia i przekazujący wartość do innego formularza:

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();

        }
    }
przybysz
źródło
2

Zakładając na przykład, że DataGridViewma kolumny, jak podano poniżej, a jego elementy powiązane z danymi są typu PrimalPallet, możesz użyć rozwiązania podanego poniżej.

wprowadź opis obrazu tutaj

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

Bezpieczniej jest uzyskać dostęp do kolumn bezpośrednio, niż używać dataGridView1.Columns["MyColumnName"]i nie ma potrzeby analizowania senderdo kolumny, DataGridViewponieważ nie jest to potrzebne.

Ryfcia
źródło
0

dobrze, ugryzę.

będziesz musiał zrobić coś takiego - oczywiście to cały metakod.

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

to „przechwytuje” metodę IClicked_My_Button_method aż do zdarzenia Click przycisku. Teraz za każdym razem, gdy zdarzenie jest „uruchamiane” z poziomu klasy owner, nasza metoda również zostanie uruchomiona.

W IClicked_MyButton_method po kliknięciu umieszczasz wszystko, co chcesz.

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

Szczegóły tutaj zależą od Ciebie, ale jeśli koncepcyjnie brakuje Ci czegoś jeszcze, daj mi znać, a postaram się pomóc.

Joshua Evensen
źródło
gdziekolwiek chcesz, żeby to połączenie miało miejsce. Ogólnie rzecz biorąc, prawdopodobnie trafiłoby to do konstruktora twojego formularza po zainicjowaniu datagridview.
Joshua Evensen
Skąd wziąłbyś guzik !?
Peter - Przywróć Monikę
0

Większość głosowanych rozwiązań jest błędna, ponieważ nie działa z kilkoma przyciskami w jednym rzędzie.

Najlepszym rozwiązaniem będzie następujący kod:

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");
            }
        }
Andrzej
źródło
0

po prostu dodaj ToList()metodę na końcu listy, gdzie połącz się z datagridview DataSource:

dataGridView1.DataSource = MyList.ToList();
nima khankhanizadeh
źródło
0

Możesz wypróbować ten, nie przejmowałbyś się zbytnio kolejnością kolumn.

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
źródło
0

Na przykład dla zdarzenia ClickCell w 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);
                }

Pozdrowienia :)

Diego Mauricio Guerrero
źródło
0

Jeśli ktoś używa C # (lub zobacz uwagę o VB.NET poniżej) i osiągnął ten punkt, ale nadal utknął, czytaj dalej.

Odpowiedź Joshuy pomogła mi, ale nie do końca. Zauważysz, że Peter zapytał „Skąd wziąłbyś guzik?”, Ale nie odpowiedział.

Jedynym sposobem, w jaki to zadziałało, było wykonanie jednej z następujących czynności, aby dodać moją obsługę zdarzeń (po ustawieniu DataSource mojego DataGridView do mojego DataTable i po dodaniu DataGridViewButtonColumn do DataGridView):

Zarówno:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

lub:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

Następnie dodaj metodę obsługi (dataGridView1_CellClick lub dataGridView1_CellContentClick) pokazaną w różnych odpowiedziach powyżej.

Uwaga: VB.NET różni się pod tym względem od języka C #, ponieważ możemy po prostu dodać klauzulę Handles do podpisu naszej metody lub wydać instrukcję AddHandler zgodnie z opisem w dokumencie „ How to: Call an Event Handler in Visual Basic ” firmy Microsoft.

clairestreb
źródło
0

Dodasz kolumnę przycisku, taką jak ta w swoim dataGridView

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


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

Następnie możesz dodać akcje do zdarzenia kliknięcia komórki. Przekonałem się, że to najłatwiejszy sposób.

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


    }

Zauważyłem, że zdarzenie Cell Click jest często subskrybowane automatycznie. Więc nie potrzebowałem tego kodu poniżej. Jeśli jednak zdarzenie kliknięcia komórki nie jest subskrybowane, dodaj ten wiersz kodu do swojego dataGridView.

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
auto9817
źródło