|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionSQL Enterprise Manager did it since years: Whenever a user changes a row in a table, it is automatically written back to the database table. Providing our users with the same functionality is tricky to implement because of the interaction of BackgroundOften, a user has to save his work explicitly, like saving a document in Word. This approach works right out of the box with Let's have a closer look at some intuitive solutions (or skip to The solution if you are in a hurry). DataGridView eventThe There would be the BindingSource eventThe data binding for the private void BindingSource_CurrentItemChanged(
object sender, EventArgs e)
{
DataRow ThisDataRow =
((DataRowView)((BindingSource)sender).Current).Row;
if (ThisDataRow.RowState==DataRowState.Modified) {
TableAdapter.Update(ThisDataRow);
}
}
If you try this code, it will work, alas for the first changed record only! You will get a strange error message during the update of the second row, basically the row seems to be empty. When you check with the debugger, the row has meaningful data before the update and only after the runtime error it seems to be empty. The update even writes the second record successfully into the database. DataTable eventIf the void Table_RowChanged
(object sender, DataRowChangeEventArgs e)
{
if (e.Row.RowState == DataRowState.Modified)
{
TableAdapter.Update(e.Row);
}
}
This time, you will immediately get a run time error. ADO.NET has not yet finished changing the The solutionIt seems that ADO.NET doesn't want to be interrupted by a row update to the database until is has completely copied the changes from the public partial class MainForm: Form {
public MainForm() {
InitializeComponent();
}
private void MainForm_Load(
object sender, EventArgs e)
{
this.regionTableAdapter.Fill(
this.northwindDataSet.Region);
// resize the column once, but allow the
// users to change it.
this.regionDataGridView.AutoResizeColumns(
DataGridViewAutoSizeColumnsMode.AllCells);
}
//tracks for PositionChanged event last row
private DataRow LastDataRow = null;
/// <SUMMARY>
/// Checks if there is a row with changes and
/// writes it to the database
/// </SUMMARY>
private void UpdateRowToDatabase() {
if (LastDataRow!=null) {
if (LastDataRow.RowState==
DataRowState.Modified) {
regionTableAdapter.Update(LastDataRow);
}
}
}
private void regionBindingSource_PositionChanged(
object sender, EventArgs e)
{
// if the user moves to a new row, check if the
// last row was changed
BindingSource thisBindingSource =
(BindingSource)sender;
DataRow ThisDataRow=
((DataRowView)thisBindingSource.Current).Row;
if (ThisDataRow==LastDataRow) {
// we need to avoid to write a datarow to the
// database when it is still processed. Otherwise
// we get a problem with the event handling of
//the DataTable.
throw new ApplicationException("It seems the" +
" PositionChanged event was fired twice for" +
" the same row");
}
UpdateRowToDatabase();
// track the current row for next
// PositionChanged event
LastDataRow = ThisDataRow;
}
private void MainForm_FormClosed(
object sender, FormClosedEventArgs e)
{
UpdateRowToDatabase();
}
}
Event analysisAs a bonus, find a trace of the events involved when the user changes the content of a cell in the DataGridView_CellBeginEdit
CellEditMode: False
DataGridView_CellValidating
CellEditMode: True
DataTable_ColumnChanging
RowState: Unchanged; HasVersion 'DCOP'
DataTable_ColumnChanged
RowState: Unchanged; HasVersion 'DCOP'
DataGridView_CellValidated
CellEditMode: True
DataGridView_CellEndEdit
CellEditMode: False
DataGridView_RowValidating
CellEditMode: False
DataTable_RowChanging
RowState: Unchanged; HasVersion 'DCOP'
BindingSource_CurrentItemChanged
RowState: Modified ; HasVersion 'DCO '
BindingSource_ListChanged
RowState: Modified ; HasVersion 'DCO '
DataTable_RowChanged
RowState: Modified ; HasVersion 'DCO '
DataGridView_RowValidated
CellEditMode: False
DataGridView_Validating
CellEditMode: False
DataGridView_Validated
CellEditMode: False
DataRow Versions:
D: Default
C: Current
O: Old
P: Proposed
Using the codeBefore you can run the sample application, open the Solution Explorer to change the Once the application is running, change the name of a region and move to another row. This will save the region name to the database. Check in the database or close and restart the application to see if the change is really stored. Don't forget to change the region name back to its original value. ConclusionThe same problem existed in earlier ADO.NET versions. I didn't try it, but the described approach should also work for earlier versions, just use the events of the History
| ||||||||||||||||||||