Как обработать событие нажатия в столбце кнопки в Datagridview?


136

Я разрабатываю приложение для Windows, используя C #. Я использую DataGridViewдля отображения данных. Я добавил столбец кнопки в этом. Я хочу знать, как я могу обработать событие нажатия на эту кнопку в DataGridView.


1
Вы добавляете кнопку программно (я подозреваю, это единственный способ)?
XstreamINsanity

Есть много ответов, доступных для этого онлайн. Что доставляет вам неприятности, в частности?
Джошуа Эвенсен

1
@ Джошуа Я получил много ответов в сети, но не понял, что делать и когда начинать. Я добавил кнопку в свое представление данных, просто не знаю, как обрабатывать событие клика.
Химадри

Ответы:


263

Вы добавили кнопку к своей DataGridViewи хотите запускать некоторый код при нажатии.
Легко peasy - просто выполните следующие действия:

Этикет:

Во-первых, вот что НЕ нужно делать:

Я бы избегал предложений, содержащихся в некоторых других ответах здесь и даже в документации MSDN, жестко закодировать индекс столбца или имя столбца, чтобы определить, была ли нажата кнопка. Событие click регистрируется для всей сетки, поэтому каким-то образом вам нужно определить, что кнопка была нажата, но вы не должны этого делать, предполагая, что ваша кнопка живет с определенным именем столбца или индексом ... есть более простой способ ...

Кроме того, будьте осторожны, какое событие вы хотите обработать. Опять же, документация и многие примеры ошибаются. Большинство примеров обрабатывают CellClickсобытие, которое сработает:

когда любая часть ячейки нажата.

... но также срабатывает при каждом щелчке по заголовку строки . Это требует добавления дополнительного кода просто для определения, если e.RowIndexзначение меньше 0

Вместо этого обработайте CellContentClickтолько то, что происходит:

когда щелкается контент внутри ячейки

По какой-либо причине заголовок столбца также считается «содержимым» в ячейке, поэтому нам все еще придется проверить это ниже.

Dos:

Итак, вот что вы должны сделать:

Сначала приведите отправителя к типу, DataGridViewчтобы раскрыть его внутренние свойства во время разработки. Вы можете изменить тип параметра, но иногда это может усложнить добавление или удаление обработчиков.

Затем, чтобы увидеть, была ли нажата кнопка, просто убедитесь, что столбец, в котором происходит событие, имеет тип DataGridViewButtonColumn. Поскольку мы уже приводим отправителя к типу DataGridView, мы можем получить Columnsколлекцию и выбрать текущий столбец, используя e.ColumnIndex. Затем проверьте, имеет ли этот объект тип DataGridViewButtonColumn.

Конечно, если вам необходимо различать несколько кнопок на сетке, вы можете выбрать их на основе имени столбца или индекса, но это не должно быть вашей первой проверкой. Всегда убедитесь, что кнопка была нажата в первую очередь, а затем обрабатывать все остальное соответствующим образом. В большинстве случаев, когда у вас есть только одна кнопка на сетке, вы можете сразу перейти к гонкам.

Собираем все вместе:

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

Обновление 1 - пользовательское событие

Если вы хотите немного повеселиться, вы можете добавить свое собственное событие, которое будет вызываться при каждом нажатии кнопки в DataGrid. Вы не можете добавить его в саму DataGrid, не запутавшись в наследовании и т. Д., Но вы можете добавить пользовательское событие в вашу форму и запустить его при необходимости. Это немного больше кода, но положительным моментом является то, что вы выделили то, что вы хотите делать при нажатии кнопки, и как определить, была ли нажата кнопка.

Просто объявите событие, поднимите его, когда это уместно, и обработайте его. Это будет выглядеть так:

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

Обновление 2 - Расширенная сетка

Что было бы здорово, если бы мы работали с сеткой, которая только что сделала это для нас. Мы могли бы ответить на первый вопрос легко: you've added a button to your DataGridView and you want to run some code when it's clicked. Вот подход, который расширяет DataGridView. Это может не стоить хлопот, связанных с необходимостью предоставлять пользовательский элемент управления для каждой библиотеки, но, по крайней мере, он максимально использует код, используемый для определения, была ли нажата кнопка.

Просто добавьте это к вашей сборке:

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

Вот и все. Никогда не трогай это снова. Убедитесь, что ваш DataGrid имеет тип, DataGridViewExtкоторый должен работать точно так же, как DataGridView. Кроме того, это также вызовет дополнительное событие, которое вы можете обработать следующим образом:

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

1
В VB.net вам не нужно проверять индекс столбца. Я использую этот точный пример для dgv с двумя столбцами. Один столбец редактируется, а второй - кнопкой удаления. Я щелкаю по всему dgv, и событие срабатывает только при нажатии на кнопку.
Светящийся

3
+1. Тем не менее, в нашем случае столбец является универсальным DataGridViewColumn, и мне пришлось проверить тип ячейки:TypeOf senderGrid.Rows(e.RowIndex).Cells(e.ColumnIndex) Is DataGridViewButtonCell
Дейв Джонсон

Судя по отзывам и комментариям, я понимаю, что это правильный ответ, но ... почему все должно быть так сложно! Я еще не подошел к WPF, но будет ли там так же?
JJ_

1
Код C # для Обновления 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); } } }
Тони Читам

@tonyenkiducx, приветствуется, но комментарии не являются хорошим местом для демонстрации альтернативного синтаксиса для всего класса, особенно такого, который можно легко получить с помощью преобразователя кода . Конечно, люди придут сюда в поисках c #, но они могут сами переходить туда и вряд ли будут просматривать комментарии в поисках реализации в любом случае. Я бы (с уважением) предложил удалить ваш комментарий
KyleMit

15

Это полностью отвечено здесь для WinForms: DataGridViewButtonColumn Class

и здесь: Как: реагировать на события кнопок в элементе управления GridView

для Asp.Net в зависимости от элемента управления, который вы на самом деле используете. (Ваш вопрос говорит о DataGrid, но вы разрабатываете приложение для Windows, поэтому используемый вами элемент управления - это DataGridView ...)


О, прости, это была моя ошибка. Я использую DataGridView. И я уже вижу первую ссылку вашего ответа. Я не попал dataGridView1_CellClickв этот код. Можете ли вы обновить свой ответ и дать мне некоторое описание.
Химадри

10

Вот лучший ответ:

Вы не можете реализовать событие нажатия кнопки для ячеек кнопки в DataGridViewButtonColumn. Вместо этого вы используете событие CellClicked объекта DataGridView и определяете, произошло ли событие для ячейки в вашем DataGridViewButtonColumn. Используйте свойство DataGridViewCellEventArgs.RowIndex события, чтобы узнать, какая строка была нажата.

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

найдено здесь: событие нажатия кнопки в datagridview


8

Это решает мою проблему.

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

5

Немного опоздал к таблице здесь, но в c # (vs2013) вам также не нужно использовать имена столбцов, на самом деле большая часть дополнительной работы, которую предлагают некоторые люди, совершенно не нужна.

Столбец фактически создается как член контейнера (форма или пользовательский контроль, в который вы поместили DataGridView). Из кода дизайнера (материал, который вы не должны редактировать, кроме случаев, когда дизайнер что-то ломает), вы увидите что-то вроде:

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;

Таким образом, в обработчике CellContentClick помимо проверки того, что индекс строки не равен 0, нужно просто проверить, действительно ли выбранный столбец является тем, который вам нужен, сравнивая ссылки на объекты:

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

Обратите внимание, что прелесть этого в том, что любые изменения имени будут отслеживаться компилятором. Если вы индексируете текстовое имя, которое изменяется или неправильно пишется с заглавной буквы, вы столкнетесь с проблемами во время выполнения. Здесь вы фактически используете имя объекта, который дизайнер создает на основе предоставленного вами имени. Но любое несоответствие будет доведено до вашего сведения компилятором.


+2 для того, чтобы быть умным, -1 для того, чтобы быть слишком умным :-) ИМХО, никогда не поздно добавить комментарий к старому сообщению, потому что много людей как я все еще ищут ответы на stackoverflow.
JonP

2

Вот мой фрагмент кода для запуска события click и передачи значения в другую форму:

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

        }
    }

2

Предположим, например, DataGridViewчто столбцы, как указано ниже, и его элементы данных связаны с типом, который PrimalPalletвы можете использовать решение, приведенное ниже.

введите описание изображения здесь

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

Безопаснее получать доступ к столбцам напрямую, чем к использованию, dataGridView1.Columns["MyColumnName"]и нет необходимости анализировать senderих, так DataGridViewкак они не нужны.


0

хорошо, я укушу

вам нужно сделать что-то вроде этого - очевидно, все это метакод.

button.Click += new ButtonClickyHandlerType(IClicked_My_Button_method)

это «подключает» метод IClicked_My_Button_method к событию Click кнопки. Теперь каждый раз, когда событие «запускается» из класса владельца, наш метод также запускается.

В IClicked_MyButton_method вы просто помещаете все, что хотите, когда вы щелкаете по нему.

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

Фактические детали здесь до вас, но если есть что-то еще, что вы упускаете концептуально, дайте мне знать, и я постараюсь помочь.


везде, где вы хотите, чтобы это произошло. Вообще говоря, это может произойти в конструкторе вашей формы после инициализации представления данных.
Джошуа Эвенсен

Откуда у тебя кнопка?
Питер - Восстановить Монику

0

Решение с большинством голосов неверно, так как не может работать с несколькими кнопками в одном ряду.

Лучшим решением будет следующий код:

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

0

просто добавьте ToList()метод в конец списка, где привязка к источнику данных datagridview:

dataGridView1.DataSource = MyList.ToList();

0

Вы можете попробовать это, вы не будете заботиться о порядке столбцов.

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

0

Например, для события ClickCell в 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);
                }

С уважением :)


0

Если кто-то использует C # (или см. Примечание о VB.NET ниже) и достиг этой точки, но все еще застрял, пожалуйста, продолжайте читать.

Ответ Джошуа помог мне, но не до конца. Вы заметите, что Питер спросил «Откуда ты взял бы кнопку?», Но остался без ответа.

Единственный способ, которым он работал для меня, это сделать одно из следующего, чтобы добавить обработчик событий (после установки DataSridView моего DataGridView в мой DataTable и после добавления DataGridViewButtonColumn в DataGridView):

Либо:

dataGridView1.CellClick += new DataGridViewCellEventHandler(dataGridView1_CellClick);

или:

dataGridView1.CellContentClick += new DataGridViewCellEventHandler(dataGridView1_CellContentClick);

Затем добавьте метод-обработчик (dataGridView1_CellClick или dataGridView1_CellContentClick), показанный в различных ответах выше.

Примечание. В этом отношении VB.NET отличается от C # тем, что мы можем просто добавить предложение Handles к сигнатуре нашего метода или выполнить инструкцию AddHandler, как описано в документе Microsoft « Как: вызвать обработчик событий в Visual Basic »


0

Вы добавите столбец кнопки, как это в вашем dataGridView

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


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

Затем вы можете добавить некоторые действия в событие клика ячейки. Я обнаружил, что это самый простой способ сделать это.

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


    }

Я обнаружил, что событие Cell Click автоматически подписывается часто. Поэтому мне не нужен этот код ниже. Однако, если ваше событие клика на ячейку не подписано, добавьте эту строку кода для вашего dataGridView.

     this.dataGridView.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView_CellClick);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.