Here is a brief explanation of my situation.
I have a updatable WinGrid with a dataset as datasource.
When a row is updated (ie: UpdateMode.OnRowChangeOrLostFocus),
I need to send the updated row to a remote server for validations and save to database.
If validations are not OK, I want the user to stay on the same row, so he can either change invalid values or cancel his changes (ESC).
If validations and save OK, then the Grid DataRow is commited (datarow.AcceptChanges), so the Grid dataset come back to an unchanged state.
At all time, i want to have only ONE row which contains modifications. I don't want the user to be able to leave a "Modified & Invalid" row.
Now my question.
I'm not sure in which WinGrid events to send the updated row to the server.
In the BeforeRowUpdate, the Grid row changes are not yet "written" to the datarow (ie: modified row are still RowState = "Unchanged" and added row are still "Detached"). The server process needs the correct RowState to save the changes to database.
In the AfterRowUpdate, the datarow state is updated as i need, and saved correctly on server. However, the problem is when there is some validation that doesn't pass, since we are in the AfterRowUpdate event, it cannot be cancelled... so i cannot force the user to stay in the invalid row to change his values or cancel his modification.
So neither events work as I would like.
Anybody have ideas how I could achieve this ?
I did manage to do what I want using the BeforeRowUpdate in the following way:
public void Grid_BeforeRowUpdate(object sender, CancelableRowEventArgs e) { // Cancel all Grid events and update the datasource row Grid.EventManager.AllEventsEnabled = false; gridRow.Update(); Grid.EventManager.AllEventsEnabled = true; // ... Send the updated datarow to server ... if (!validationOK) { // Simulate a change in any cell so the Row.DataChanged is set back to true string s = gridRow.Cells[0].Text; gridRow.Cells[0].Value = null; gridRow.Cells[0].Value = s; // Cancel the event se the user stay on the row e.Cancel = true; return; } //... }
However, I am not sure how robust is this solution and if there is some better alternative.
Thanks,
Guillaume.
Hi Guillaume,
Data access in DotNet is really not set up to do what you want here. It's really set up to do batch updating. So the grid doesn't really have an event for what you want.
I think you would probably have to use the AfterRowUpdate event and if the data fails to validate, you would have to reload the data somehow into the DataSet to update the grid.
Hi Mike,
Do you think my working solution may be too hazardous, ie: is not supported behavior and may stop working in future version ?
Btw, is there a simpler way to programmaticaly set the row DataChanged property ?
Ok, if it's better to use the AfterRowChange event, instead of trying to prevent the user of leaving the grid row, i could prevent him of modifying other rows, when modifications are pending. Then on the OnAfterRowCancelUpdate of the modified row, I would simply reject the changes of the datarow, to put back the initial values in the grid.
The CancelUpdate I was referring to is on the DataSet, not the grid. You are right that once you call Update on the grid, calling CancelUpdate on the grid would have no effect. But just as the grid keeps changes and then sends them to the data source, a DataSet keeps the changes and eventually sends them to the back end.
Thanks for your input,
My question was more if it's hazardous to manually call the gridRow.Update() inside the OnBeforeRowUpdate event.
No matter if I do the back end update in batch or row by row, I still have the same problem, which is:
- OnBeforeRowUpdate: is cancelable but the changes are not yet in the local datasource, so i cannot send to back end for save;
- OnAfterRowUpdate: changes are written in the local datasource, but the event is not cancelable.
You mention about CancelUpdate(), i cannot use this in the OnAfterRowUpdate event because the Update() has already been called, so the update are already commited to the local datasource. The only way I know to revert back to original is the use the datarow.RejectChanges().
From what I understand, this is the order of events when updating a row:
- datarow.BegindEdit()
- gridrow.OnBeforeRowUpdate() -> datarow have a DataRowVersion.Proposed
- gridrow.Update()
- datarow.EndEdit() -> update the datarow.RowState
- gridrow.OnAfterRowUpdate()
I think it would be interesting to have documentation on all the sequence of events when updating a row.
Anyway, for my current problem, I have 2 alternatives that should work. I just wanted to know if I wasn't doing crazy things.
Thanks again,
Guillaume
I don't know if it's that hazardous. But the standard in DotNet is to do updates in batches, not update a single row at a time. At least, that's the standard between the data source and the back end. I couldn't say whether this will change, that's really outside my area of expertise. I know more about the interaction between the grid and the data source than the data source and the back end.
The grid only deals with the local data source. So it will update it whenever you change rows or cell or when you tell it to. The interaction between the data source and the back end is beyond the scope of the grid.
If you are using a DataSet as your data source, I wonder if you could just call CancelUpdate on it. That should revert the values in any edited rows to their original values and notify the grid of the change.