The linked DataGridView table generates a single RowChanged event when double-clicked. How can I do it?

I have a DataGridView whose DataSource is a DataTable. This DataTable has a boolean column that is interpreted as a flag in the DataGridView.

employeeSelectionTable.Columns.Add("IsSelected", typeof(bool)); ... employeeSelectionTable.RowChanged += selectionTableRowChanged; dataGridViewSelectedEmployees.DataSource = employeeSelectionTable; ... private void selectionTableRowChanged(object sender, DataRowChangeEventArgs e) { if ((bool)e.Row["IsSelected"]) { Console.Writeline("Is Selected"); } else { Console.Writeline("Is Not Selected"); } break; } 

When the user makes one click on the checkbox, he gets the checkbox, and selectionTableRowChanged displays "Is Selected".

Similarly, when the user checks it again, the window is cleared and the SelectionTableRowChanged exits "Not Selected".

Here where I have a problem:

When the user double-clicks the flag, the flag is set, the RowChanged event occurs ("Selected"), and then the flag is cleared and the corresponding RowChanged event is not raised. The RowChanged event subscriber is now out of sync.

My solution right now is to subclass DataGridView and override WndProc to have WM_LBUTTONDBLCLICK, so any double click on the control is ignored. Is there a better solution?

+4
source share
7 answers

The reason that creating an empty DoubleClick event method does not help will be performed in addition to other operations that occur when you double-click.

If you look at the code generated by Windows, or at examples of programmatically adding event handlers, you use + = to assign an event handler. This means that you add this event handler in addition to others that already exist, you could fire several event handlers in a save event.

My instinct would be to override the DataGridView class, then override the OnDoubleClick method and not call the base OnDoubleClick method.

However, I tested it very quickly and see some interesting results.

I put together the following test class:

 using System; using System.Windows.Forms; namespace TestApp { class DGV : DataGridView { private string test = ""; protected override void OnDoubleClick(EventArgs e) { MessageBox.Show(test + "OnDoubleClick"); } protected override void OnCellMouseDoubleClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e) { MessageBox.Show(test + "OnCellMouseDoubleClick"); } protected override void OnCellMouseClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e) { if (e.Clicks == 1) { // Had to do this with a variable as using a MessageBox // here would block us from pulling off a double click test = "1 click "; base.OnCellMouseClick(e); } else { MessageBox.Show("OnCellMouseClick"); } } } } 

Then I inserted this into the window form, adding a checkbox column and running the program.

On a new start, double-clicking on the flag displays the message on "1 click OnDoubleClick".

This means that OnCellMouseClick is executed in the first part of the double-click, and then OnDoubleClick is executed in the second click.

In addition, unfortunately, deleting the call to the basic methods does not seem to prevent the checkbox from getting the click passed to it.

I suspect that for this approach to work, it may have to be taken further and redefined by DataGridViewCheckBoxColumn and DataGridViewCheckBoxCell, which ignores double-clicking. Assuming this works, you could stop double-clicking on the checkbox, but still allow it on other column controls.

I posted an answer to another question that talks about creating custom columns and DataGridView cells in here .

+2
source

If you need a checkbox column inside a DataGridView, create something like this:

 DataGridViewCheckBoxCell checkBoxCell = new MyDataGridViewCheckBoxCell(); ... DataGridViewColumn col = new DataGridViewColumn(checkBoxCell); ... col.Name = "colCheckBox"; ... this.dgItems.Columns.Add(col); 

where dgItems is an instance of a DataGridView.

As you can see, I have a class MyDataGridViewCheckBoxCell, which is a subclass of the DataGridViewCheckBoxCell class. In this subclass, I define:

 protected override void OnContentDoubleClick(DataGridViewCellEventArgs e) { //This the trick to keep the checkbox in sync with other actions. //base.OnContentDoubleClick(e); } 

When the user now double-clicks the checkbox in the checkbox column, the checkbox will behave as if it were one click away. This should solve your sync problem.

+2
source

This is not an entirely elegant solution, but why not just do the following?

 private void dgv_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { dgv_CellClick(sender, e); } 

This would clearly force the second CellClick event and avoid synchronization.

+2
source

Is there any reason why this needs to be done at a low level? Can a DoubleClick method be an empty method that eats it?

+1
source

I already tried to override the OnDoubleClick method in the DataGridView subclass to do nothing, but it still allowed me to change the checkbox a second time.

Ideally, I was looking for the DataTable RowChanged event to be raised twice. Is there a way to affect the underlying DataTable using the overridden OnDoubleClick method?

+1
source

Why not just leave the IsSelected column unlimited? Use the CellContentClick event to output data to the underlying data type and leave the CellDoubleClick or RowChange event.

 private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e) { if(e.ColumnIndex == <columnIndex of IsSelected>) { string value = dgv[e.ColumnIndex, e.RowIndex].EditedFormattedValue; if( value == null || Convert.ToBoolean(value) == false) { //push false to employeeSelectionTable } else { //push true to employeeSelectionTable } } } 
+1
source

I don't know why I should have, but I managed to add a timer event related to updating the datagridview, which just updated dgv after the second click.

In an event with a mouse click

 ** _RefreshTimer = new Timer(); _RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick); _RefreshTimer.Interval = 100; _RefreshTimer.Start(); } } } void RefreshTimer_Tick(object sender, EventArgs e) { dgv.Refresh(); _RefreshTimer.Stop(); _RefreshTimer = null; }** 
+1
source

Source: https://habr.com/ru/post/1277298/


All Articles