Обрабатываем ввод данных в колонку чекбоксов DataGridView - C#, checkbox colum, CurrentCellDirtyStateChanged

Имеем сетку DataGridView связанную с некой DataTable через BindingSource. Один из столбцов DataGridView содержит chekbox'ы - в нем надо ставить галочки. При изменении значения в любой ячейке этого столбца, включая удаление и добавление строк, надо проделать некие вычисления по данным DataGridView (точнее говоря связанной с ним DataTable), включая количество отмеченных chekbox'ов.

По умолчанию подобный столбец ведет себя крайне неестественно для конечного пользователя. Точнее говоря, на него распространяется стандартная модель поведения - зашли в ячейку, начали редактировать, закончили редактировать выйдя из ячейки или нажав Enter. Вот только все редактирование chekbox ограничивается одним мышиными кликом, на экране галочка ставится, но изменение данных происходит только при выборе другой ячейки или нажатии Enter. Нормального способа решения этой проблемы нет - все события, включая CellValueChanged, CellClick не позволяют получить доступ к измененному значению chekbox до выхода из режима редактирования.

Что можно сделать? За исключением использования (или написания с нуля) нестандартного DataGridView, остается всего два варианта:

1) Писать свой собственный обработчик клика по ячейке с checkbox, определяющий ее координаты и самостоятельно заносящий изменения в связанную DataTable, полностью отключая стандартную обработку. То есть делаем колонку read-only, вешаемся на событие клика по ячейке, проверяем колонку и строку кликнутой ячейки и вручную пишем 0 или 1 в соответствеющую ячейку DataTable, которая служит источником данных для грида

2) Садиться на событие CurrentCellDirtyStateChanged - отслеживающие черновое изменение данных в выбранной ячейке и вручную вызывать другое событие CellValueChanged

if (someDataGridView.IsCurrentCellDirty)
{
    someDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
    gridDataSorceDataTable.AcceptChanges();// если используем DataTable и нужно передавать изменения дальше, например в другие DataView и гриды
}

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

В частности, начинает очень странно работать удаление строк. Как бы я ни удалял строки, методами BindingSource или DataTable - удаленные столбцы помечаются как detached и при последующем чтении данных из DataTable (простой обход в цикле) передаются считывающей строки функции, вызывая критическую ошибку RowNotInTableException - то есть строка уже удалена.

Вылечить это удалось только проверкой состояния строки в цикле, перебирающем эти самые строки

if (currRow.RowState == DataRowState.Detached) { continue; } 

Кроме того, начинаются странности при редактировании ячеек в других столбцах. Приходится вешать на CurrentCellDirtyStateChanged проверку столбца столбца, и вызывать CellValueChanged только столбца чекбоксов.

Другой вариант - пересчитывать значения не по самой DataTable, а по выбранному из нее массиву строк DataRow[]. Для выборки используем метод Select() с пустым фильтром.

DataRow[] selRows = someDataSet.someDataTable.Select();
foreach (DataRow currRow in selRows) 
{
 // обработка данных
}

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


Комментарии

Обрабатываем ввод данных в колонку чекбоксов DataGridView - C#, checkbox colum, CurrentCellDirtyStateChanged — Комментарии (4)

  1. Так то все нормально. Не могу разобраться с событием CurrentCellDirtyStateChanged - как отследить когда пользователь поставил галочку, чтобы в смежных ячейках сделать чекбоксы не доступными

  2. А что именно непонятно? Я просто проверяю, в какой именно колонке оно произошло, и если это колонка с чекбоксами принудительно завершаю изменение данных в ячейке - вызывая стандартное событие CellValueChanged. А вся дальнейшая обработка вешается на это событие - так как при нем данные в ячейке уже изменились, галка проставилась/снялась и можно на основании ее значения выполнять какие-то действия.

  3. Я добавил вызов Грид.CommitEdit(блаблабла.Commit) в событии CellContentClick. В отличии от CellClick он срабатывает когда щелкаешь именно на флажке.

Добавить комментарий для Ведомир Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *


*

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>