Как обнаружить флажок элементом управления datagridview событие изменения?


у меня есть приложение winforms и я хочу вызвать некоторый код, когда флажок встроен в DataGridView контроль checked или unchecked. Каждое событие я пробовал либо

  1. срабатывает, как только CheckBox щелкается, но до того, как его проверенное состояние изменится, или
  2. срабатывает только один раз CheckBox теряет фокус

Я не могу найти событие, которое срабатывает сразу после того как проверил состояние изменения.


Edit:

то, что я пытаюсь достичь, это когда проверенное состояние a CheckBox в одном DataGridView изменения, данные в двух других DataGridViews изменения. Но все события, которые я использовал, данные в других сетках меняются только после CheckBox в первом DataGridView теряет фокус.

15 61

15 ответов:

обработки DatGridViews CheckedChanged событие вы должны сначала получить CellContentClick огонь (который не имеет CheckBoxes текущее состояние!) тогда звоните CommitEdit. Это, в свою очередь, огонь CellValueChanged событие, которое вы можете использовать для выполнения своей работы. это недосмотр со стороны Microsoft. Сделайте что-нибудь вроде следующего...

private void dataGridViewSites_CellContentClick(object sender, 
    DataGridViewCellEventArgs e)
{
    dataGridViewSites.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

/// <summary>
/// Works with the above.
/// </summary>
private void dataGridViewSites_CellValueChanged(object sender, 
    DataGridViewCellEventArgs e)
{
    UpdateDataGridViewSite();
}

Я надеюсь, что это помогает.

P. S. проверить эту статью https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged(v=vs. 110).aspx

Я нашел решение @Killercam для работы, но был немного изворотливым, если пользователь дважды щелкнул слишком быстро. Не уверен, что другие нашли, что дело тоже. Я нашел другое решение здесь.

Он использует в DataGrid CellValueChanged и CellMouseUp. Чанхун объясняет, что

" причиной этого является OnCellvalueChanged событие не будет срабатывать, пока DataGridView думает, что вы завершили редактирование. Это делает смысл для столбца текстового поля, как OnCellvalueChanged не будет [беспокоиться] стрелять для каждого ключевого удара, но это не [имеет смысла] для флажка."

вот он в действии из его примера:

private void myDataGrid_OnCellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    {
        // Handle checkbox state change here
    }
}

и код, чтобы сообщить флажку, что он редактируется при нажатии, вместо того, чтобы ждать, пока пользователь покинет поле:

private void myDataGrid_OnCellMouseUp(object sender,DataGridViewCellMouseEventArgs e)
{
    // End of edition on each click on column of checkbox
    if (e.ColumnIndex == myCheckBoxColumn.Index && e.RowIndex != -1)
    {
        myDataGrid.EndEdit();
    }
}

решение jsturtevants отлично сработало. Тем не менее, я решил сделать обработку в событии EndEdit. Я предпочитаю этот подход (в моем приложении), потому что, в отличие от события CellValueChanged, событие EndEdit не срабатывает во время заполнения сетки.

вот мой код (часть которого украдена из jsturtevant:

private void gridCategories_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    {
        //do some stuff
    }
}



private void gridCategories_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == gridCategories.Columns["AddCategory"].Index)
    {
        gridCategories.EndEdit();
    }
}

Это также обрабатывает активацию клавиатуры.

    private void dgvApps_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        if(dgvApps.CurrentCell.GetType() == typeof(DataGridViewCheckBoxCell))
        {
            if (dgvApps.CurrentCell.IsInEditMode)
            {
                if (dgvApps.IsCurrentCellDirty)
                {
                    dgvApps.EndEdit();
                }
            }
        }
    }


    private void dgvApps_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
          // handle value changed.....
    }

после Killercam'Answer, мой код

private void dgvProducts_CellContentClick(object sender, DataGridViewCellEventArgs e)
    {
        dgvProducts.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }

и :

private void dgvProducts_CellValueChanged(object sender, DataGridViewCellEventArgs e)
    {
        if (dgvProducts.DataSource != null)
        {
            if (dgvProducts.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "True")
            {
                //do something
            }
            else
            {
               //do something
            }
        }
    }

все дело в редактировании ячейки, проблема в том, что ячейка не редактировалась на самом деле, поэтому вам нужно сохранить изменения ячейки или строки, чтобы получить событие, когда вы нажимаете флажок, чтобы вы могли использовать эту функцию:

datagridview.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)

при этом вы можете использовать его даже с другим событием.

Я нашел простой ответ на эту проблему. Я просто использую обратную логику. Код находится в VB, но он не сильно отличается от C#.

 Private Sub DataGridView1_CellContentClick(sender As Object, e As 
 DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick

    Dim _ColumnIndex As Integer = e.ColumnIndex
    Dim _RowIndex As Integer = e.RowIndex

    'Uses reverse logic for current cell because checkbox checked occures 
     'after click
    'If you know current state is False then logic dictates that a click 
     'event will set it true
    'With these 2 check boxes only one can be true while both can be off

    If DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False And 
       DataGridView1.Rows(_RowIndex).Cells("Column3").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False
    End If

    If DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False And 
    DataGridView1.Rows(_RowIndex).Cells("Column2").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False
    End If


End Sub

одна из лучших вещей об этом нет необходимости для нескольких событий.

вот код:

private void dgvStandingOrder_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    if (dgvStandingOrder.Columns[e.ColumnIndex].Name == "IsSelected" && dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
    {
        bool isChecked = (bool)dgvStandingOrder[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
        if (isChecked == false)
        {
            dgvStandingOrder.Rows[e.RowIndex].Cells["Status"].Value = "";
        }
        dgvStandingOrder.EndEdit();
    }
}

private void dgvStandingOrder_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{

    dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
}

private void dgvStandingOrder_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dgvStandingOrder.CurrentCell is DataGridViewCheckBoxCell)
    {
        dgvStandingOrder.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
}

то, что сработало для меня было CurrentCellDirtyStateChanged в сочетании с datagridView1.EndEdit()

private void dataGridView1_CurrentCellDirtyStateChanged( object sender, EventArgs e ) {
    if ( dataGridView1.CurrentCell is DataGridViewCheckBoxCell ) {
        DataGridViewCheckBoxCell cb = (DataGridViewCheckBoxCell)dataGridView1.CurrentCell;
        if ( (byte)cb.Value == 1 ) {
            dataGridView1.CurrentRow.Cells["time_loadedCol"].Value = DateTime.Now.ToString();
        }
    }
    dataGridView1.EndEdit();
}

код будет цикл в DataGridView и будет проверять, если флажок столбец проверен

private void dgv1_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
    if (e.ColumnIndex == 0 && e.RowIndex > -1)
    {
        dgv1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        var i = 0;
        foreach (DataGridViewRow row in dgv1.Rows)
        {
            if (Convert.ToBoolean(row.Cells[0].Value))
            {
                i++;
            }
        }

        //Enable Button1 if Checkbox is Checked
        if (i > 0)
        {
            Button1.Enabled = true;
        }
        else
        {
            Button1.Enabled = false;
        }
    }
}

в случае CellContentClick вы можете использовать эту стратегию:

private void myDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{    
    if (e.ColumnIndex == 2)//set your checkbox column index instead of 2
    {   //When you check
        if (Convert.ToBoolean(myDataGrid.Rows[e.RowIndex].Cells[2].EditedFormattedValue) == true)
        {
            //EXAMPLE OF OTHER CODE
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = DateTime.Now.ToShortDateString();

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 1;
        }
        else //When you decheck
        {
            myDataGrid.Rows[e.RowIndex].Cells[5].Value = String.Empty;

            //SET BY CODE THE CHECK BOX
            myDataGrid.Rows[e.RowIndex].Cells[2].Value = 0;
        }
    }
}

для этого при использовании devexpress xtragrid необходимо обработать EditValueChanged событие соответствующего элемента репозитория, как описано здесь. Важно также, чтобы позвонить в управления gridview1.PostEditor() метод, чтобы обеспечить измененное значение был размещен. Вот реализация:

        private void RepositoryItemCheckEdit1_EditValueChanged(object sender, System.EventArgs e)
        {
            gridView3.PostEditor();

            var isNoneOfTheAboveChecked = false;

            for (int i = 0; i < gridView3.DataRowCount; i++)
            {
                if ((bool) (gridView3.GetRowCellValue(i, "NoneOfTheAbove")) && (bool) (gridView3.GetRowCellValue(i, "Answer")))
                {
                    isNoneOfTheAboveChecked = true;
                    break;
                }
            }

            if (isNoneOfTheAboveChecked)
            {
                for (int i = 0; i < gridView3.DataRowCount; i++)
                {
                    if (!((bool)(gridView3.GetRowCellValue(i, "NoneOfTheAbove"))))
                    {
                        gridView3.SetRowCellValue(i, "Answer", false);
                    }
                }
            }
        }

обратите внимание, что поскольку xtragrid не предоставляет перечислитель, необходимо использовать цикл for для итерации по строкам.

Я нашел простой ответ на эту проблему. Я просто использую обратную логику. Код находится в VB, но он не сильно отличается от C#.

 Private Sub DataGridView1_CellContentClick(sender As Object, e As 
 DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick

    Dim _RowIndex As Integer = e.RowIndex

    'Uses reverse logic for current cell because checkbox checked occures 
     'after click
    'If you know current state is False then logic dictates that a click 
     'event will set it true
    'With these 2 check boxes only one can be true while both can be off

    If DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False And 
       DataGridView1.Rows(_RowIndex).Cells("Column3").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False
    End If

    If DataGridView1.Rows(_RowIndex).Cells("Column3").Value = False And 
    DataGridView1.Rows(_RowIndex).Cells("Column2").Value = True Then
        DataGridView1.Rows(_RowIndex).Cells("Column2").Value = False
    End If


End Sub

одна из лучших вещей об этом нет необходимости для нескольких событий.

удаление фокуса после изменения значения ячейки позволяет обновить значения в DataGridView. Удалите фокус, установив CurrentCell в null.

private void DataGridView1OnCellValueChanged(object sender, DataGridViewCellEventArgs dataGridViewCellEventArgs)
{
    // Remove focus
    dataGridView1.CurrentCell = null;
    // Put in updates
    Update();
}

private void DataGridView1OnCurrentCellDirtyStateChanged(object sender, EventArgs eventArgs)
{
    if (dataGridView1.IsCurrentCellDirty)
    {
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }

}

вы можете заставить клетки, чтобы зафиксировать значение, как только вы установите флажок, а затем поймать CellValueChanged событие. Элемент CurrentCellDirtyStateChanged срабатывает, как только вы установите флажок.

следующий код работает для меня:

private void grid_CurrentCellDirtyStateChanged(object sender, EventArgs e)
    {
        SendKeys.Send("{tab}");
    }

затем вы можете вставить свой код в CellValueChanged событие.