DataGridView capturing user row selection - c#

I am having trouble handling the selections in DataGridView.
My grid view contains an amount column. There is a textbox on the form which should display the total amount of the selected grid view rows. Hence I need to capture events when the user selects/ deselects the gridview rows and calculate (add/ subtract) the amount accordingly. I have found two methods of doing it:
Using the RowEnter and RowLeave events.
These work fine when user selects/ deselects a single row. However, when the user is selecting multiple rows at one go, the event gets fired only for the last row. Hence, from my total amount only the amount in the last row gets added/ subtracted. Thus making my result erroneous.
Using the RowStateChanged event.
This works for multiple rows. However, the event gets fired event if the user scrolls through the datagrid.
Has anyone handled such a scenario. I would like to know which datagrid event I should be using, so that my code executes only when user selects/ deselects rows including multiple rows.

Found the solution. I can use RowStateChanged and run my code only if StateChanged for the row is Selected...
private void dgridv_RowStateChanged(object sender, DataGridViewRowStateChangedEventArgs e)
{
// For any other operation except, StateChanged, do nothing
if (e.StateChanged != DataGridViewElementStates.Selected) return;
// Calculate amount code goes here
}

I use SelectionChanged event or CellValueChanged event:
dtGrid.SelectionChanged += DataGridView_SelectionChanged;
this.dtGrid.DataSource = GetListOfEntities;
dtGrid.CellValueChanged += DataGridView_CellValueChanged;
private void DataGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridViewRow row = dtGrid.Rows[e.RowIndex];
SetRowProperties(row);
}
private void DataGridView_SelectionChanged(object sender, EventArgs e)
{
var rowsCount = dtGrid.SelectedRows.Count;
if (rowsCount == 0 || rowsCount > 1) return;
var row = dtGrid.SelectedRows[0];
if (row == null) return;
ResolveActionsForRow(row);
}

I think you can consider the SelectionChanged event:
private void DataGridView1_SelectionChanged(object sender, EventArgs e) {
textbox1.Text = DataGridView1.SelectedRows.Count.ToString();
}

You can use SelectionChanged event and retrieve the row index of the selected cell(s):
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if (dataGridView1.SelectedCells.Count > 0)
Do_Something_With_It(dataGridView1.SelectedCells[0].RowIndex);
}

You can simply capture this in following way, but it is restricted to single row selection only:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
MessageBox.Show("Selected row is=" + e.RowIndex);
// you can perform (any operation) delete action on selected row like
dataGridView1.Rows.RemoveAt(e.RowIndex);
dataGridView1.Refresh();
}

You can use your first method (row enter row leave) along with the SelectedRows property. Meaning, when you detect those events, and you need to calculate, instead of using the row from the event args, loop through the SelectedRows and get your total.

Related

ADO.NET TableAdapter Updating on CellValueChanged Event for a DataGridView

I have a DataGridView which includes a checkbox column for a Boolean variable in the database.
When I click on this checkbox, it fires the events below.
Inside the uiPersonGridView_CellValueChanged event, I call the Data Table Adapter Update method on the Persons Data Table which is the Datasource for the DataGridView.
The Update works fine, the second time but it will still not Update the Current Rows Data?
For example, if I had two rows, if I tick in the first rows check box; Update returns 0 rows updated for int i and I check the database and nothing has been changed. But if I tick on the second rows check box, the Update returns 1 row updated for int i - I check the database and the first record has changed and not the second?
How can I get it work so the update works for the initial change and changes thereafter?
private void uiPersonGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (uiPersonGridView.IsCurrentCellDirty)
{
uiPersonGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void uiPersonGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (uiPersonGridView.DataSource == null)
return;
if (e.RowIndex == -1)
return;
int i = _personAdapter.Update(_person);
}
What I had to do in order to get this working was set the datarow state to modified and this has done what I need it to do.
private void uiPersonGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (uiPersonGridView.IsCurrentCellDirty)
{
uiPersonGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
DataRowView drv = uiPersonGridView.CurrentRow.DataBoundItem as DataRowView;
drv.Row.SetModified();
}
}

Datagridview Datagridcheckbox cell values not matching GUI

I have a unbound DataGridView with 6 columns, the first being a DataGridCheckBoxColumn. When a user clicks on a checkbox cell, I want to determine what cells have been checked and what ones are not. Here is my code:
private void UpdateSelectedPlaces()
{
//Clear out the places list each time the user selects a new item (or items)
_selectedPlaces.Clear();
foreach (DataGridViewRow row in placesGridView.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.Equals(true))
{
_selectedPlaces.Add((TripPlace)row.DataBoundItem);
}
}
}
//Click event handler
private void placesGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
UpdateSelectedPlaces();
}
I am finding that the DataGridCheckBoxCells are not holding the correct value at the time of the click. This occurs for all rows. There seems to be no pattern really. I was hoping that the event was just not called at the right time (I.e. the checking of the checkbox was yet to be completed) but I cannot prove that.
In short, even though the GUI displays a checked checkbox, the back end thinks the checkbox is not checked when using .Value Is there a simpler way to just determine if each cell[0] is checked or not checked in a datagridview?
I am finding that the DataGridCheckBoxCells are not holding the
correct value at the time of the click.
This is normal and by design because you are using DataGridView.CellContentClick event. From MSDN:
Use this event to detect button clicks for a DataGridViewButtonCell or
link clicks for a DataGridViewLinkCell. For clicks in a
DataGridViewCheckBoxCell, this event occurs before the check box
changes value, so if you do not want to calculate the expected value
based on the current value, you will typically handle the
DataGridView.CellValueChanged event instead. Because that event occurs
only when the user-specified value is committed, which typically
occurs when focus leaves the cell, you must also handle the
DataGridView.CurrentCellDirtyStateChanged event.
The corrected code is similar to the other answer but unfortunately, the reason of the problem was not explained in that answer.
private void UpdateSelectedPlaces()
{
//Clear out the places list each time the user selects a new item (or items)
_selectedPlaces.Clear();
foreach (DataGridViewRow row in placesGridView.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.Equals(true))
{
_selectedPlaces.Add((TripPlace)row.DataBoundItem);
}
}
}
private void placesGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
UpdateSelectedPlaces();
}
private void placesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (placesGridView.IsCurrentCellDirty)
{
placesGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void placesGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
Boolean bl;
if (placesGridView.Columns[e.ColumnIndex].Name == "name of check column")
{
DataGridViewCheckBoxCell checkCell = (DataGridViewCheckBoxCell)placesGridView.Rows[e.RowIndex].Cells[2]; //2 number of check column
//bl is the check box current condition.
//Change only this in your list eg list[e.RowIndex] = bl; No need to check all rows.
bl = (Boolean)checkCell.Value;
}
}
private void placesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (placesGridView.IsCurrentCellDirty)
{
placesGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}

c# .net datagridview SelectionChanged

I'm racking my head over something that should be pretty simple to do. Its been a day now so I finally give up and I will ask the question. How can I actually trigger the selectionChanged event on the datagridview in .net?
I would basically like to grab the row values when the user double-clicks/ or single clicks any where on a row. but I cant for the life of me get this event to fire even tough I read here that this should be the even I need to use?
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
foreach (DataGridViewRow row in AddrGrid.SelectedRows)
{
string value1 = row.Cells[0].Value.ToString();
string value2 = row.Cells[1].Value.ToString();
//...
}
}
I have tried something similar to this but im hopeless I click on the datagrid cells or rows and this does not fire what I'm I missing?
when I click on a cell I get this event to fire.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
Addresses.aTyp = AddrGrid.Rows[AddrGrid.CurrentCell.RowIndex].Cells["Address Type"].Value.ToString();
Addresses.seq = AddrGrid.Rows[AddrGrid.CurrentCell.RowIndex].Cells["Sequence"].Value.ToString();
}
But I like to capture the double click or click on a row not just a cell.
Any help would be most appreciated.
private void dataGridView_SelectionChanged(object sender, EventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
string value1 = row.Cells[0].Value.ToString();
string value2 = row.Cells[1].Value.ToString();
}
}
you can use this
private void AddrGrid_CellEnter(object sender, DataGridViewCellEventArgs e)
{
Addresses.aTyp = AddrGrid.Rows[AddrGrid.CurrentCell.RowIndex].Cells["Address Type"].Value.ToString();
Addresses.seq = AddrGrid.Rows[AddrGrid.CurrentCell.RowIndex].Cells["Sequence"].Value.ToString();
}
On your grid object lets call it 'foo'. You will do something like..
foo.SelectionChanged += dataGridView1_SelectionChanged
you will need to do that somewhere to wire the event up. I normally do it in the constructor for the form
Many answers relating to the selectionchanged event for a DataGridview use "DG1.SelectedRows(0)". This is fundementally wrong. There may be multiple rows selected and the first selected row may not be the newly selected row. Unless you want to parse over all of the selected rows each time, "DG1.Rows(DG1.CurrentCell.RowIndex)" should be used

DataGridViewCheckBoxCell how to show checked when set during form load

I have a DataGridView that loads data from a DataTable, along with an unbound column of DataGridViewCheckBoxCells. The rows in the DataGridView are compared with a separate DataTable with values the user has saved, and if there is a match, the checkbox for that row should check.
Here is the code that compares the values and sets the checkbox value to 'true':
foreach (int j in selectedObjectives)
{
foreach (DataGridViewRow r in dgvObjectives.Rows)
{
if (j == Convert.ToInt32(r.Cells["ObjectiveID"].Value))
{
dgvObjectives.CurrentCell = r.Cells["Select"];
((DataGridViewCheckBoxCell)r.Cells["Select"]).Value = true;
//dgvObjectives.InvalidateCell(r.Cells["Select"]);
//dgvObjectives.EndEdit();
//dgvObjectives.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
if (Convert.ToInt32(r.Cells["ObjectiveID"].Value) == selectedIndex)
{
r.Selected = true;
}
}
}
When I call the method to perform this action during the form load private void WQMDrill_Load(object sender, EventArgs e), the values are set correctly, but the checkboxes do not check. However, when called after the form is finished loading, the code works perfectly. Unfortunately for me, I absolutely need for these to check during the load process.
I hope I was clear with my issue, any help on this matter would be greatly appreciated. As you can see, I have tried to invalidate the cell alone, as well as the entire DataGridView control. I also have
private void dgvObjectives_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (this.dgvObjectives.CurrentCell.ColumnIndex == 0)
{
this.dgvObjectives.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
That doesn't fire during this time. Thank you.
You can put your checkbox selection and update logic in the DataBindingComplete eventhandler, this fires after the FormLoad but before anything is displayed to the user.
I'm not certain that calling CommitEdit will actually fire the Paint on the cell. Try handling the CellMouseUp event and firing EndEdit if the column is a checkbox column.
private void dgvObjectives_CellMouseUp(object sender, DataGridViewCellMouseEventArgs e)
{
if (dgvObjectives.Columns[e.ColumnIndex] is DataGridViewCheckBoxColumn)
{
dgvObjectives.EndEdit();
}
}
I had the same problem, and tried a lot of different ways to deal with it, most failed, except when I tried this.BeginInvoke(new CDelegate()).

Triggering a checkbox value changed event in DataGridView

I have a grid view that has a check box column, and I want to trigger a drawing event as soon as the value of the cell is toggled. I tried the ValueChaged and the CellEndEdit and BeginEdit, and chose the selection mode as CellSelect. As for the the first 2 events, the event was triggered upon the finishing of the edit mode, like moving out of the current cell, or going back and forth. It's just a weird behavior.
Is there anything that triggers the event on the grid view as soon as the cell value is changed?
I use the CellContentClick event, which makes sure the user clicked the checkbox. It DOES fire multiple times even if the user stays in the same cell. The one issue is that the Value does not get updated, and always returns "false" for unchecked. The trick is to use the .EditedFormattedValue property of the cell instead of the Value property. The EditedFormattedValue will track with the check mark and is what one wishes the Value had in it when the CellContentClick is fired.
No need for a timer, no need for any fancy stuff, just use CellContentClick event and inspect the EditedFormattedValue to tell what state the checkbox is going into / just went into. If EditedFormattedValue = true, the checkbox is getting checked.
A colleague of mine recommends trapping the CurrentCellDirtyStateChanged event. See http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx.
Another way is to handle the CellContentClick event (which doesn't give you the current value in the cell's Value property), call grid.CommitEdit(DataGridViewDataErrorContexts.Commit) to update the value which in turn will fire CellValueChanged where you can then get the actual (i.e. correct) DataGridViewCheckBoxColumn value.
private void grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// do something with grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value
}
Target .NET framework: 2.0
Small update.... Make sure you use EditedFormattedValue instead of value as I tried value but it never give right status that is checked/unchecked most of the site still use value but as used in latest c# 2010 express below is one way to access..
grdJobDetails.Rows[e.RowIndex].Cells[0].EditedFormattedValue
Also _CellValueChanged event suggested or used by few must be usable for some cases but if you are looking for every check/uncheck of cell make sure you use _CellContentClick else per my notice I see not every time _CellValueChanged is fired.. that is if the same checkbox is clicked over & over again it does not fire _CellValueChanged but if you click alternately for example you have two chekbox & click one after other _CellValueChanged event will be fired but usually if looking for event to fire everytime the any cell is check/uncheck _CellValueChanged is not fired.
Try hooking into the CellContentClick event. The DataGridViewCellEventArgs will have a ColumnIndex and a RowIndex so you can know if a ChecboxCell was in fact clicked. The good thing about this event is that it will only fire if the actual checkbox itself was clicked. If you click on the white area of the cell around the checkbox, it won't fire. This way, you're pretty much guaranteed that the checkbox value was changed when this event fires. You can then call Invalidate() to trigger your drawing event, as well as a call to EndEdit() to trigger the end of the row's editing if you need that.
I finally implemented it this way
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
if (dataGridView1[e.ColumnIndex, e.RowIndex].GetContentBounds(e.RowIndex).Contains(e.Location))
{
cellEndEditTimer.Start();
}
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{ /*place your code here*/}
private void cellEndEditTimer_Tick(object sender, EventArgs e)
{
dataGridView1.EndEdit();
cellEndEditTimer.Stop();
}
I had the same issue, but came up with a different solution:
If you make the column or the whole grid "Read Only" so that when the user clicks the checkbox it doesn't change value.
Fortunately, the DataGridView.CellClick event is still fired.
In my case I do the following in the cellClick event:
if (jM_jobTasksDataGridView.Columns[e.ColumnIndex].CellType.Name == "DataGridViewCheckBoxCell")
But you could check the column name if you have more than one checkbox column.
I then do all the modification / saving of the dataset myself.
"EditingControlShowing" event doesn't fire on checkbox value change. Because display style of the checkbox cell doesn't not change.
The workaround i have used is as below. (I have used CellContentClick event)
private void gGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (string.Compare(gGridView1.CurrentCell.OwningColumn.Name, "CheckBoxColumn") == 0)
{
bool checkBoxStatus = Convert.ToBoolean(gGridView1.CurrentCell.EditedFormattedValue);
//checkBoxStatus gives you whether checkbox cell value of selected row for the
//"CheckBoxColumn" column value is checked or not.
if(checkBoxStatus)
{
//write your code
}
else
{
//write your code
}
}
}
The above has worked for me. Please let me know if need more help.
I found a simple solution.
Just change the cell focus after click on cell.
private void DGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == "Here checkbox column id or name") {
DGV.Item(e.ColumnIndex, e.RowIndex + 1).Selected = true;
//Here your code
}
}
Don't forget to check if the column of your (ckeckbox + 1) index exist.
Every one of the CellClick and CellMouseClick answers is wrong, because you can change the value of the cell with the keyboard and the event will not fire. Additionally, CurrentCellDirtyStateChanged only fires once, which means if you check/uncheck the same box multiple times, you will only get one event. Combining a few of the answers above gives the following simple solution:
private void dgvList_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvList.CurrentCell is DataGridViewCheckBoxCell)
dgvList.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void dgvList_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// Now this will fire immediately when a check box cell is changed,
// regardless of whether the user uses the mouse, keyboard, or touchscreen.
//
// Value property is up to date, you DO NOT need EditedFormattedValue here.
}
cellEndEditTimer.Start();
this line makes the datagridview update the list of checked boxes
Thank you.
I found a combination of the first two answers gave me what I needed. I used the CurrentCellDirtyStateChanged event and inspected the EditedFormattedValue.
private void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridViewCell cell = dgv.CurrentCell;
if (cell.RowIndex >= 0 && cell.ColumnIndex == 3) // My checkbox column
{
// If checkbox checked, copy value from col 1 to col 2
if (dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue != null && dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue.Equals(true))
{
dgv.Rows[cell.RowIndex].Cells[1].Value = dgv.Rows[cell.RowIndex].Cells[2].Value;
}
}
}
Use this code, when you want to use the checkedChanged event in DataGrid View:
private void grdBill_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grdBill.CurrentCell = grdBill.Rows[grdBill.CurrentRow.Index].Cells["gBillNumber"];
}
private void grdBill_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
calcBill();
}
private void calcBill()
{
listBox1.Items.Clear();
for (int i = 0; i < grdBill.Rows.Count - 1; i++)
{
if (Convert.ToBoolean(grdBill.Rows[i].Cells["gCheck"].Value) == true)
{
listBox1.Items.Add(grdBill.Rows[i].Cells["gBillNumber"].Value.ToString());
}
}
}
Here, grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox in Grid (Second column).
So, when we want to fire checkchanged event for each click, first do the CellContentClick it will get fire when user clicked the Text box, then it will move the current cell to next column, so the CellEndEdit column will get fire, it will check the whether the checkbox is checked and add the "gBillNumber" in list box (in function calcBill).
Working with an unbound control (ie I manage the content programmatically), without the EndEdit() it only called the CurrentCellDirtyStateChanged once and then never again; but I found that with the EndEdit() CurrentCellDirtyStateChanged was called twice (the second probably caused by the EndEdit() but I didn't check), so I did the following, which worked best for me:
bool myGridView_DoCheck = false;
private void myGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (!myGridView_DoCheck)
{
myGridView_DoCheck = true;
myGridView.EndEdit();
// do something here
}
else
myGridView_DoCheck = false;
}
Using the .EditedFormattedValue property solves the problem
To be notified each time a checkbox in a cell toggles a value when clicked, you can use the CellContentClick event and access the preliminary cell value .EditedFormattedValue.
As the event is fired the .EditedFormattedValue is not yet applied visually to the checkbox and not yet committed to the .Value property.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
bool isChecked = (bool)checkbox.EditedFormattedValue;
}
The event fires on each Click and the .EditedFormattedValue toggles

Categories

Resources