I'm using the following code to commit cell changes to the database and calculate the value of another cell in the database. While I realize it isn't the norm to store a calculated value, I haven't been able to find a way to calculate the cell at the database level.
private void dgvPlayers_CellValidated(object sender, DataGridViewCellEventArgs e)
{
this.Validate();
.
.
.
playerListBindingSource.EndEdit();
playerListTableAdapter.UpdatePlayerAvg(Convert.ToDecimal(average), Convert.ToDecimal(dgvPlayers.Rows[e.RowIndex].Cells[0].Value));
playerListTableAdapter.Update(dsPlayerTeam.PlayerList);
this.playerListTableAdapter.Fill(this.dsPlayerTeam.PlayerList);
}
}
The problem I've run into is that TableAdapter.Fill method causes unexpected changes to the cell focus. If I'm tabbing through the fields, everything works as expected, however if I use the cursor keys to change rows, then the focus will shift to a different column, usually (but not always) the first column.
I thought I could store the row and column indexes of the current cell and key pressed in a keydown event then manually set the focus at the end of my CellValidated handler. What I found was that the keydown event I attached to the DataGridView was never called probably because the DataGridView is actually a collection of controls. This was what I tried:
dgvPlayers.KeyDown += new KeyEventHandler(dgvPlayers_KeyDown);
.
.
.
private void dgvPlayers_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
DataGridView theGrid = (DataGridView)sender;
dgvPlayersKeyPress = e.KeyCode;
}
Since I was never able to collect the Key press, I was never able to manually set the focus.
Are there any other options here? Perhaps there's a way to refresh the bound data for a specific cell rather than .Fill for the whole tableadapter?
I still haven't found a suitable solution to this problem. Does anyone have a recommendation? What I've come to understand is that the cell that when it performs the .Fill, it clears the table, then regenerates the rows which explains the strange focus behaviour. I'm starting to think that I should unbind the datagridview, and manually read and write data to the database. I would really prefer to avoid this.
ThanX!
Related
I am using the DataGridView Control for reading and writing an XML file through XML Serialization.
I have an issue as explained below:
I read an XML file and populate DataGridView controls with the deserialized object.
I update all the values on the DataGridView on the cell.
I choose the File Save As option without losing focus on the last cell.
After this, the value of the particular cell is not updated. If I intentionally shift focus away (say I click on another cell on the same grid) the value is updated.
Can anyone suggest any solution for this?
The best way (though quick and dirty) is to assign the currentCell value to Nothing.
For example, in the save method, do:
dgvMyGrid.CurrentCell = Nothing
and then proceed further.
It's because the edited cell value is not committed to the DataSource until it's validated, which happens when the cell lose focus. If you want to commit the modifications immediately, you can handle the CurrentCellDirtyStateChanged event, and call the CommitEdit method in the handler :
void dataGridView1_CurrentCellDirtyStateChanged(object sender,
EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
If I understand you correctly, a cell is in editing mode and you're trying to programmatically stop editing and pass the value to the underlying datasource?
I'm using a somewhat "dirty" approach to do that in one of my applications:
if (dataGridView1.CurrentCell.IsInEditMode)
{
int y = dataGridView1.CurrentCellAddress.Y;
int x = dataGridView1.CurrentCellAddress.X;
if (y > 0)
dataGridView1.CurrentCell = dataGridView1.Rows[y - 1].Cells[x];
else
dataGridView1.CurrentCell = dataGridView1.Rows[y + 1].Cells[x];
dataGridView1.CurrentCell = dataGridView1.Rows[y].Cells[x];
}
That piece of code first checks whether the current cell is in edit mode. Then it changes the current cell programmatically (either to the previous row or the next row in case we're in the first row). After that, it restores the current cell selection.
You would call this code in your "File Save As" handler.
I had the same situation and I was even using accelerator keys for save button for saving the grid values. When I click on Save button focus lost from DGV and hence cell value is committed, but when I use accelerator keys focus doesn't lost from DGV hence no committing of the cell value.
After looking at the Amit Karmakar answer out of curiosity I tried that answer and it worked. To find out more details I went into debugging of the DGV and found that it is really same thing as commitedit which somehow doesn't work if you use it in the save button click.
When we set CurrentCell of DGV to null, before setting it to null DGV first gets the edited value and pushes it in to cell value and then sets CurrentCell REFERENCE to null. Here it doesn't mean that it is setting underlying DGV cell to null. Hence this works perfectly for the above problem.
Note: This solution may not work perfectly when you have validating events for the cell and if user enters invalid data which will fail validation. In this case setting current cell to null also fails as it cannot push the value to cell.
I gave this explanation as I've raised question on Amit Karmakar answer asking how can it be possible. I thought it may help some other, so dropped this explanation as answer.
OK, this is UGLY but it works to get the FINAL CHANGES from the grid WITHOUT having to move to another row:
With DataGridView1
.DataSource = Nothing
.DataSource = gridDataTable
Dim changedFoo As DataTable = gridDataTable.GetChanges
End With
However I still like the answer from Amit Karmakar the best.
I've added the 'DataGridView1.CurrentCell = Nothing' to the DataGridView1 LostFocus event.
You can get the value of a cell which is not yet committed using the EditedFormattedValue property for the current cell, as below
dataGridView1.CurrentCell.EditedFormattedValue
I have a datagridview loaded from the SQL Server database containing an editable column. I want to check if the user has changed the data in the datagridview and after that i can save the data back to the database, and if the user hasn't changed anything then it won't save the data to the database. I don't want to update the data on the original records, after changes in the datagridview it should insert the data back to the database. Something like master and user templates.
DataGridViewCell does not track changes. If you need to know that Value has changed for one cell only, use CellValueChanged event and do your stuff there. If you need to know which cells have been modified, so you can enumerate them and do what is necessary, try this:
HashSet<DataGridViewCell> changedCells = new HashSet<DataGridViewCell>();
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = sender as DataGridView;
if (!changedCells.Contains(dgv[e.ColumnIndex, e.RowIndex]))
{
changedCells.Add(dgv[e.ColumnIndex, e.RowIndex]);
}
}
Don't forget to hook to CellValueChanged event of DataGridView. When you need a list of changed cells, do this:
foreach (DataGridViewCell cell in changedCells)
{
// Your work here
}
This works on UI level only. You will need different approach if your data gets changed by code also.
See here for complete reference
See the [Nikola Markovinović][2] answer
I think you can use the OnRowUpdating="GridViewUpdateEventHandler" of the asp.net grid.
If a user leaves a row where they made changes to any cells in the datagridview control, I want to ask them to save the changes and then save the changes.
The problem is that I can not find the elusive and magical combination of properties and events to get this to work. When I try to call the save routine from events like RowValidating, RowValidated, RowLeave, or RowStateChanged, the value of the changed cells, or at least the value of the last cell in the row, is not the new value.
It comes up as the old value before it was changed. It seems to be canceling the edit.
I did look at similar questions here but they did not address my issue. Can someone please help and advise on the best way, or a good way to accomplish this???
Thank you!
Valhalla
Add an event handler for RowLeave as such:
private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
{
if (this.dataGridView1.IsCurrentRowDirty)
{
this.dataGridView1.EndEdit();
// Your prompt to save code.
}
}
I have a DataGridView which I need to run a CellValidating event to ensure that only valid values are selected from a ComboBox. This is needed as the ComboBox contains dummy rows used to display the category, with the fields the user can select listed underneath each category.
Whilst I have the validation code working fine, there is an unwelcome side-effect that all values are being wiped from the row being validated. I have stripped the code in the Event handler down to this, and the issue still occurs:
private void dgvInformation_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DataGridView dgv = this.dgvInformation;
DataGridViewCell cell = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex];
}
If I remove the
DataGridViewCell cell = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex];
line then the issue does not occur.
The DGV is unbound which I believe is causing the issue. As a test I have made a simple form and populated the DGV values unbound, and each time the CellValidating event fires that row is wiped out, but when I create a List<> and use that as the DataSource the values are not wiped out. Could this be a bug with unbound DGVs?
Many thanks
I have problems with the sentense: "to ensure that only valid values are selected from a ComboBox." Using a combobox should actually prevent wrong values beeing tipped in controls like textbox, why dont you just show valid values in the combobox, or validate after all sellections have been made if you need to validate a combination of comboboxes sellection, therefor you may need somthing like a Submit button to run the validation routine.
If you still think you have to validate the combobox after each sellection then you ahve to run the validation somehow on a SelectionChanged event of the combobox.
I have a DataGridView with a CellEndEdit function that updates my database. However, it only works if the user clicks off the edited cell onto a different row. If the user presses Return on the keyboard, the change is lost.
I have looked at the variables in debug mode and found that pressing Return does set everything the same as clicking the next row. Any ideas would be great!
Update Method:
private void Grd_RawLedger_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
{
raw_LedgerTableAdapter.Update(belvan_GL_EEA_M12DataSet.Raw_Ledger);
this.raw_LedgerTableAdapter.Fill(this.belvan_GL_EEA_M12DataSet.Raw_Ledger);
}
Have you tried using the RowValidated Event instead of the CellEndEdit Event?
This should do what you are asking, the only big difference is that instead of saving per cell change it will save per row change. You would also need to make sure that you are only saving things that have changed.