Як обробити подію натискання у стовпці кнопки у Datagridview?


136

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


1
Ви додаєте кнопку програмно (як я підозрюю, це єдиний спосіб)?
XstreamINsanity

Є багато відповідей для цього в Інтернеті. Що, зокрема, створює проблеми?
Джошуа Евенсен

1
@Joshua Я отримав багато відповідей в мережі, але насправді не здогадувався, що робити і коли почати. Я додав кнопку в моєму перегляді даних, просто не знаю, як обробляти його подія клацання.
Хімадрі

Відповіді:


263

Ви додали кнопку до свого DataGridViewі хочете запустити якийсь код при натисканні на нього.
Легкий горошок - просто виконайте наступні дії:

Не потрібно:

По-перше, ось що НЕ робити:

Я б уникнув пропозицій у деяких інших відповідях тут і навіть наданих документацією на MSDN для жорсткого кодування індексу чи назви стовпців, щоб визначити, чи натиснули кнопку. Подія натискання реєструється для всієї сітки, тож якимось чином потрібно визначити, що була натиснута кнопка, але цього не слід робити, вважаючи, що ваша кнопка живе у певній назві або індексі стовпця ... є простіший спосіб ...

Крім того, будьте уважні, з якою подією ви хочете вчинити. Знову ж таки, документація та багато прикладів помиляються. Більшість прикладів стосується CellClickподії, яка спричинить пожежу:

коли клацніть будь-яку частину комірки.

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

Замість цього обробіть те, CellContentClickщо відбувається лише:

при натисканні на вміст у комірці

З будь-якої причини заголовок стовпця також вважається "вмістом" всередині комірки, тому нам все одно доведеться перевірити це нижче.

Дос:

Отже, ось що вам потрібно зробити:

По-перше, відправте відправника типу, 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); } } }
Tony Cheetham

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

знайдено тут: подія натискання кнопки в перегляді даних


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 за занадто розумність :-) IMHO ніколи не пізно додати коментар до старої публікації, тому що багато людей, як я, все ще шукають відповіді на stackoverflow.
JonP

2

Ось мій фрагмент коду, щоб запустити подію натискання та передати значення іншій формі:

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 аж до події Клік. Тепер, кожного разу, коли подія буде "запущена" з класу власників, наш метод також буде запущений.

У методі 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.
}

Фактичні деталі тут залежать від вас, але якщо ви ще чогось не вистачаєте, то концептуально пропустіть, повідомте мене, і я спробую допомогти.


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

Звідки ти взяв би кнопку !?
Пітер - Відновіть Моніку

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

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.

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 нижче) і досяг цього, але все ще затримався, будь ласка, читайте далі.

Відповідь Джошуа мені допомогла, але далеко не всім шляхом. Ви помітите, що Петро запитував: "Звідки б ви взяли кнопку?", Але не відповів.

Єдиний спосіб, який він працював для мене, - це зробити одне з наступного, щоб додати мій посилання для подій (після встановлення джерела даних 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.