#c_sharp #winforms #datagridview #события
Конечно, напрашивается ответ: "используй другое событие", но, к сожалению, я не нашёл подходящий event. Живой пример из живой программы: есть таблица настроек, у которой есть колонка типа checkbox. Требуется, чтобы при изменении состояния чекбокса, кнопка Save на форме Enabled = true; Проблема заключается в том, что когда вы нажимаете мышкой на checkbox, событие DataGridView.CellValueChanged не вызывается, пока ячейка не потеряет фокус. Cell.Value ещё хранит прежнее значение и никаких событий обновления данных не возникает. Новое значение хранится в свойстве Cell.EditedFormattedValue, но оно появляется там только после выполнения всех событий, которые я тестировал. Напросилось такое решение: private void gridSettings_CellClick(object sender, DataGridViewCellEventArgs e) { var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(() => { Thread.Sleep(200); }) .ContinueWith(result => { if (gridSettings.Columns[e.ColumnIndex].Name == "ColumnIsMandatory") { var clickedCell = gridSettings.Rows[e.RowIndex].Cells[e.ColumnIndex]; object editedValue = clickedCell.EditedFormattedValue; object oldValue = clickedCell.Value; if (oldValue != null && editedValue != null && (bool) editedValue != (bool) oldValue) { clickedCell.Value = (bool) editedValue; // Событие изменения данных вызвано принудительно } } }, uiScheduler); } Но оно обладает недостатками в виде запуска Task и отфонарного Thread.Sleep(200); который не гарантирует, что данные уже обновились. Да и решение топорное, совсем не изящное. Как бы вы решали такую проблему? UPDATE: Работающий пример: public partial class Form1 : Form { private DataGridView gridSettings; private Button buttonSave; public Form1() { InitializeComponent(); gridSettings = new DataGridView() { Location = new Point(0,0), Size = new Size(200, 200) }; var column = new DataGridViewCheckBoxColumn() { Name = "ColumnIsMandatory" }; gridSettings.Columns.Add(column); gridSettings.Rows.Add(1); buttonSave = new Button {Text = "Save", Location = new Point(210, 210), Enabled = false}; gridSettings.CellValueChanged += (sender, args) => buttonSave.Enabled = true; gridSettings.CellClick += gridSettings_CellClick; this.Controls.AddRange(new Control[]{gridSettings, buttonSave}); } private void gridSettings_CellClick(object sender, DataGridViewCellEventArgs e) { var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(() => { Thread.Sleep(200); }) .ContinueWith(result => { if (gridSettings.Columns[e.ColumnIndex].Name == "ColumnIsMandatory") { var clickedCell = gridSettings.Rows[e.RowIndex].Cells[e.ColumnIndex]; object editedValue = clickedCell.EditedFormattedValue; object oldValue = clickedCell.Value; if (oldValue != null && editedValue != null && (bool)editedValue != (bool)oldValue) { clickedCell.Value = (bool)editedValue; // Событие изменения данных вызвано принудительно } else if (oldValue == null && editedValue != null) { clickedCell.Value = (bool)editedValue; } } }, uiScheduler); } }
Ответы
Ответ 1
Если я не ошибаюсь, вам способ прекрасно работает, даже если из обработчика CellClick выкинуть создание тасков. То есть достаточно оставить оператор if. Тем не менее, событие, которое вам нужно - CurrentCellDirtyStateChanged. gridSettings.CurrentCellDirtyStateChanged += GridSettings_CurrentCellDirtyStateChanged; private void GridSettings_CurrentCellDirtyStateChanged(object sender, EventArgs e) { buttonSave.Enabled = true; }
Комментариев нет:
Отправить комментарий