Click here to Skip to main content
Click here to Skip to main content

Auto Saving DataGridView Rows to a SQL Server Database

By , 26 Jan 2006
 

Introduction

SQL 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 DataSet and BindingSource, which is hardly documented in the .NET help. This article investigates some intuitive solutions and explains why they will not work. A detailed analysis of the involved events leads to the final solution, which is surprisingly simple as any good solution should be.

Background

Often, a user has to save his work explicitly, like saving a document in Word. This approach works right out of the box with DataRowViews, using the save button of the BindingNavigator. But saving explicitly can be cumbersome for the user if changes in a DataRow should be updated immediately to the database. Implementing auto saving should be easy! Just use an event which detects that the row content has changed, use the Update method of the TableAdapter and you are done. Unfortunately, ADO.NET will run into some strange internal errors should you try it.

Let's have a closer look at some intuitive solutions (or skip to The solution if you are in a hurry).

DataGridView event

The DataGridView would be the most obvious choice to detect that a row has changed in the DataGridView. But the DataGridView focuses mostly on a cell, displaying its content, the user interaction and writing back the changed data to DatSet.DataTable.DataRow. Events like DataGridView_RowValidated fire for all possible reasons, and not necessarily because the user has changed the data.

There would be the DataGridView_CellEndEdit event indicating a change. But using TableAdapter.Update() at this point of time will mess up ADO.NET. Updating the database would happen in the middle of copying from the DataView to the DataTable. Both activities change the state of the DataRow. Interrupting the copy with the update will prevent the copy operation from finishing properly (I guess ADO.NET doesn't support reentrancy).

BindingSource event

The data binding for the DataGridView is done in the BindingSource, the right place to detect when the content of a cell has changed:

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 event

If the BidingSource doesn't work, how about using an event from the DataSet.DataTable? After all, any change to the DataRow should be written to the database, regardless of who does it. The code could look like this:

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 DataRow when the Update tries to change the state of the DataRow again.

The solution

It 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 DatRowView to the DataTable. None of the row change related events can be used to save the row to the database. So the solution must be to use an event which fires after the row is copied and the event should not be related to the row changed! Well, then let's just use the PositionChanged event of the BindingSource. It fires for the next row the user navigates to. So the challenge is to remember which was the last row, check if it was modified and update the database if needed. Don't forget to do the same thing when the Form closes, the PositionChanged event will not fire when the Form closes:

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 analysis

As a bonus, find a trace of the events involved when the user changes the content of a cell in the DataGridView:

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 code

Before you can run the sample application, open the Solution Explorer to change the NorthwindConnectionString. The DataSource should point to your SQL server with the Northwind database.

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.

Conclusion

The 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 CurrencyManager.

History

  • 27.1.2006: Original posting.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Peter Huber SG
Web Developer
Singapore Singapore
Member
SW Dev Manager from Switzerland living in Singapore
 
I would be very interested to do SW development in Singapore for an international .NET project.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionMaster-Slave, how to do itmemberdherrmann12 Mar '13 - 8:16 
Hi Peter,
I have a master-slave construction. Your solution works for the master-table, but not for slave-table.
Because of this:
bsMaster.DataSource = DataSet.Tables(tableName)
bsSlave.DataSource = bsMaster
bsSlave.DataMember = RelationName 'a relation
(bs.. BindingSource)
 
What to do?
Regards-
Dietrich
QuestionInterestingmemberMember 365653120 Sep '12 - 10:53 
I found a better way, at least for me.
 
Use DataGridViewCellValidating()
 
First validate your data.
If the input is the correct type, compare it to the original value:
if bindingsource("YourField") = Cell.EditedFormattedValue Then
Return
End IF
I parse the formatted value back to the same type before comparing.
 
If that passes, check business rules, do an update, then any post triggers like updating totals or other fields etc...
QuestionThanks, it is very usefull sample and guidancemembersanthosh19698 Aug '12 - 4:15 
I was nearly lost with auto saving data from DataGridview, thanks for the help for posting. Smile | :)
Questionneed to helpmemberaminsoro5 Mar '12 - 1:29 
hello. i am amin tafteh from iran. i need to program smart timetabling for schools with c# and wpf . how to write sql to automate schedule ? can you help me ? do you have sample to help me? how to schedule teachers without Interference ?please help me. i need it
QuestionSimple methodmemberJasmine250113 Nov '11 - 17:17 
Use the wizard to set up your DataGridView, bind it to your table. Then simply add this...
 
private void MyDataGridView_RowValidated(object sender, DataGridViewCellEventArgs e) {
     if (myDataSet.GetChanges() != null) {
         myTableAdapter.Update(myDataSet);
     }
}
 
In my application, this was being hit whenever the user moved from one row to the next, and when you closed the application. Works for adding new rows also.
AnswerRe: Simple methodmemberBrianGoodheim9 Dec '12 - 8:21 
Jasmine2501, Thanks for the advice on your simple handler. My application was handling all kinds of events and duplicating records inadvertently until I used only the dgv_rowvalidated event. Thanks.
BugWhat about deleted, added and detached?memberMrDeej19 Aug '11 - 3:30 
This code is not a true datagridview saver. This just modifies existing records.
GeneralMy vote of 5memberHiraHaque5 Jul '11 - 4:50 
Very helpfull and well organized.......Thank you
GeneralThanksgroupYZK30 Mar '11 - 0:06 
Thanks
NewsAlternative to Form.FormClosed event is Component.Disposed eventmemberskewty23 Mar '10 - 19:18 
My code was inside a DataGridView so I didn't have easy access to the Form.FormClosed event.
 
I was able to achieve the same thing by using Component.Disposed event.
 
Hopefully this saves somebody else some time.
 
Scott
GeneralRe: Alternative to Form.FormClosed event is Component.Disposed eventmemberdajvid7 Nov '12 - 23:09 
Using the same concept, I shifted the call to UpdateRowToDatabase to the BindingSource's Disposed event instead of the FormClosed (which I don't have in a user control) or Component.Disposed (because I don't want modify in the automatically generated code of the designer) event.
QuestionAnother DB please?memberi_microsoft27 Feb '10 - 11:19 
Can u please help me in updating Access database by datagridview in C# windows application?
AnswerRe: Another DB please?memberRaviRanjankr5 Apr '11 - 7:16 
While searching a solution I got your question. yeah! you can easily update your database by datagridview.
take a look there Add, Edit, and Delete in DataGridView</a>[<a href="http://www.codeguru.com/csharp/.net/net_data/datagrid/article.php/c13041" target="_blank" title="New Window">^</a>] to read superb article how to modify your database by datagridview.
QuestionVersion for Visual studio 2008memberfrancis bohorquez15 Dec '09 - 10:36 
There is a version to visual studio 2008 ? because there are some converting errors between versions
 
Thank you in advance.
QuestionTrouble adding a row to empty datagridviewmemberEZ175221 Jul '09 - 12:07 
Above code works great when editing (or adding) rows in a non-bound datagridview. My problem is when I try to add to an empty grid the row state is detached. If there are several rows existing this doesn't happen and using the LastRow.DataState works great.
 
Anyone have an idea why this is happening?
 
thanks
Questionis this better solution?membermekklot18 May '09 - 22:30 
Hello!
 
I have just wrote this:
private void myBindingSource_CurrentChanged(object sender, EventArgs e)
{
 my_ListTableAdapter.Update(myDataSet);
}
It works with Add, Delete, Update rows. But I assume this might be slower than just updating rows...please write your opinions about this!
 
Thanks
mekklot
QuestionNot getting the PositionChanged eventmemberSam Lambert7 Mar '08 - 14:32 
Admittedly, I'm a newbie with C# and .NET (despite coding for almost 30 years), but I can't seem to get the PositionChanged event to fire.
 
I've got the following defined:

dataGridView1.DataSource = bindingSource1;
bindingSource1.PositionChanged += bindingSource1_PositionChanged;

My event handler never gets invoked. I've got a ListChanged event handler on the BindingSource that fires when I do a Fill(), and a RowsAdded event on the datagrid that fires off appropriately, but I cannot get this other handler to work.
 
Any suggestions?
 
-- Sam
AnswerRe: Not getting the PositionChanged eventmemberpah_lee27 Aug '08 - 20:35 
You should try this:
 
{
...
dataGridView1.DataSource = bindingSource1;
bindingSource1.PositionChanged += new EventHandler(bindingSource1_PositionChanged);
...
}
 
void bindingSource1_PositionChanged(object sender, EventArgs e)
{
//put your code here
}
 
PaLee
Generalvb solutionmemberAl Kearns14 Jan '08 - 9:55 
Hi,
 
Was looking for a solution for this problem but in VB - once converted, it worked great. Although the code provided only covered editing existing records, adding functionality for adding new rows was quite simple (in fact I used a Select... Case statement and trapped the Edit and AddNew in one case)
 
code is as follows:
 

Private Sub UpdateRowToDatabase()
 
If Not IsNothing(LastDataRow) Then
 
Select Case LastDataRow.RowState
 
Case DataRowState.Modified, DataRowState.Added
 
ClientsTableAdapter.Update(LastDataRow)
 
End Select
 
End If
 
End Sub
 
Private Sub ClientsBindingSource_PositionChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles ClientsBindingSource.PositionChanged
 
Dim bsClients As BindingSource = CType(sender, BindingSource)
Dim row As DataRowView
row = bsClients.Current
Dim ThisDataRow As DataRow = row.Row
 
If ThisDataRow.Equals(LastDataRow) Then
 
'don't write a datarow while it is still being processed
'problems with event handling of the DataTable will occur
Throw New ApplicationException("It seems the" + _
" PositionChanged event was fired twice for" + _
" the same row")
 
End If
 
'update row and save it for next time thru
UpdateRowToDatabase()
LastDataRow = ThisDataRow
 
End Sub
 
Private Sub frmMain_FormClosed(ByVal sender As Object, _
ByVal e As System.Windows.Forms.FormClosedEventArgs) _
Handles Me.FormClosed
 
UpdateRowToDatabase()
 
End Sub

QuestionRe: vb solutionmemberlumartineru4 Oct '08 - 19:07 
Hi,
 
I'm testing a very simple datagridview (3 columns). I am able to retrieve data but not save it to database. I'm using your VB code, changed for my proposes, but I get two errors in the UpdateRowToDatabase function:
 
First, LastDataRow is not declared. Where do I declare it? Where do I set o VS2005 sets a value to it?
 
Second, I replace the adapter name using mine (myAdapter) but I'm finding the same problem: it is not declared. I'm using myAdapter to retrieve the data but in the Load form event.
 
Hopefully you can help me. I've spend several hours trying to update the datagridview changes.
 
Luis
QuestionRowLeave ?memberandycted22 Oct '07 - 22:49 
I suppose you could use RowLeave to check when the selected row has changed ? and maybe track if cells have been edited with CellBeginEdit and CellEndEdit ?
I'm not sure but it seems to work for me right now...

 
Andy
AnswerRe: RowLeave ?memberandycted17 Nov '07 - 2:28 
Actually saving modifications by handling RowLeave gives me some problems when working with multiple controls. I'm actually trying BindingSource.CurrentChanged (not BindingSource.CurrentItemChanged) with a certain degree of success until now.
Andy
 
Andrea Sabbatini
Sviluppo software - Software development
www.andreasabbatini.com
www.doctorsoffice.it

GeneralAdding new rows to the DataGridView UImemberSubrahmanyam K10 Oct '07 - 21:50 
Hi Peter,
 
Very nice article.
 
Besides updating the existing rows, I have the requirement of adding new rows to the DataGridViews User Interface which internally gets added to the underlying datasource.
 
Here is my requirement in detail:
 
I have a requirement to add new rows to the DataGridView UI which is bound to a DataTable.
 
The new row added to the UI should get added to the underlying DataSource.
 
I have bound the DataGridView to a DataSource.
 
The DataSource consists of 10 columns out of which only 5 columns were bound to the DataGridView.
 
The other 5 columns which are not bound consists of composite primary key on 2 columns and 3 other columns will not accept null values.
 

 
I have tried with "DefaultValueNeede" event of the DataGridView to define the default values for the new row.
 
As only 5 columns are bound to the DataGridView, I could supply the default values only to those columns.
 
How would I supply the default values to the rest of the columns which are not bound to the DataGridView?
 
Which event of the DataGridView should be handled in this scenario?
 
An exception is thrown when I tried to commit the new row in the DataGridView UI (by adding a "new new row") to the DataGrid.
 
The exception is that "Required values are not supplied to the new DataRow" which are the composite primary key columns (2) and "not null" columns (3).
 

Thank You.
 
Subrahmanyam K

GeneralRe: Adding new rows to the DataGridView UImemberMomony7 Dec '07 - 11:57 
I had that similar problem of specifying default values for columns in the datatable that were not in the datagridview.
 
I did handled the DataGridView's Default values needed, and retrieved the underlying datatable row from the bindingsource's Current property.
 
The code looked like this:
private void HandleGridViewDefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
{ if (e.Row.IsNewRow)
{ DataRowView currentRowView = BindingSource.Current as DataRowView;
MyTableRow currentRow = currentRowView.Row as MyTableRow
object currentID = currentRow["MyIDColumn"];
if (Convert.IsDBNull(currentID))
{ currentRow["MyIDColumn"] = Guid.NewGuid();
}
}
}
 
Hope that helps,
-Kent
QuestionGreat article ... but what about prompting before saving?memberseehsarp10 Jun '07 - 3:10 
Hi,
 
your article is very good. I searched for some solution on a similar problem.
I want the user to decide if the changed data should be saved, rejected or modified again. Therefore I wrote these lines in the CurrentItem_Changed Handler of my BindingSource:
 

DataRow ThisDataRow = ((DataRowView)bs.Current).Row;
if (ThisDataRow != LastDataRow)
{
if (LastDataRow != null && LastDataRow.RowState == DataRowState.Modified)
{
switch (MessageBox.Show("Do you want to save \"" + LastDataRow["Name"] + "\"?",
"Last item " + LastDataRow["IDData"] + " has unsaved changes:",
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
{
case DialogResult.Yes: saveData(); /*calls Update-method*/ break;
case DialogResult.No: LastDataRow.RejectChanges(); break;
/// AT THIS POINT THE LAST DATA ROW IS RE-OPENED, WHICH WORKS - ALMOST.
case DialogResult.Cancel: bs.Position = LastDRowPos; return;
 
}
}
 
LastDataRow = ThisDataRow; /// Saves last row
LastDRowPos = bs.Position; /// Saves Position of last row
}

 
This really works fine, but my only problem occures when the user answers "Cancel" (I know that it isn't too smart to change the bindingsource position in the very same handler ): The bindingsource seems to be changed properly. Only my datagridview still selects the old row!!! And if I want to change this manually by datagridview.Row[LastDRowPos].Cells[0].Selected = true; I get a InvalidOperationException.
 
Help, anyone please?
GeneralThanks - Great article, just what I needed!memberCSutherland6 Jun '07 - 7:09 
Thanks - Great article, just what I needed!
GeneralCant get it to update my db.memberJon Henry14 May '07 - 14:41 
I cant get it to update my db. Anyone see anything wrong?
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Printing;
 
namespace Paintball
{
public partial class fclsinv : Form
{
// The class that will do the printing process.
DataGridViewPrinter MyDataGridViewPrinter;

public fclsinv()
{
InitializeComponent();
}
private void fclsinv_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'paintballDataSet.Inventory' table. You can move, or remove it, as needed.
this.inventoryTableAdapter.Fill(this.paintballDataSet.Inventory);
// resize the column once, but allow the users to change it.
this.TheDataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
private void timer1_Tick(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'paintballDataSet.Inventory' table. You can move, or remove it, as needed.
this.inventoryTableAdapter.Fill(this.paintballDataSet.Inventory);
}

//tracks for PositionChanged event last row
private DataRow LastDataRow = null;

/// Checks if there is a row with changes and writes it to the database
private void UpdateRowToDatabase()
{
if (LastDataRow != null)
{
if (LastDataRow.RowState == DataRowState.Modified)
{
this.inventoryTableAdapter.Update(LastDataRow);
}
}
}
private void inventoryBindingSource_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)inventoryBindingSource.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 btnclose_Click(object sender, EventArgs e)
{
UpdateRowToDatabase();
}
 
Jon Henry
GeneralRe: Cant get it to update my db.memberElphabah30 Aug '07 - 15:24 
My code looks just like yours, and mine also doesn't work. I'll be interested in any response.

 
Elph
QuestionValidate the row?memberanders@sms10 Apr '07 - 21:53 
When do you validate the row before saving it to the DB?
 
I tried to add "this.Validate()" before the save... but that gave me all sorts of trouble.
 
Any ideas?
 
Anders...
GeneralAnother approachmemberbamboozle6 Jan '07 - 2:36 
- Use VirtualMode
- Use the RowValidating event in conjunction with IsCurrentRowDirty to detect update attempts
- Update the database yourself
- If it succeeds - DataTable.AcceptChanges()
- If it fails - e.Cancel = true;
- handle CancelRowEdit with DataTable.RejectChanges()
- Proposed values are here: this.gridOne.Rows[e.RowIndex].Cells[i].Value
- Current values are here: this.dt.Rows[e.RowIndex][i, DataRowVersion.Original]
- Now Microsoft's Dirty Pen bug is fixed because you can implement RowDirtyStateNeeded correctly
 
This is the grid 99% of WinForms actually need.
 
Whoever designed DataGridView should get a new job, outside of software development.
 

QuestionRe: Another approachmemberYahshuatwo22 Mar '07 - 3:32 
Bamboozle:
 
How can your approach be done using dataadapters?
 

Poke tongue | ;-P

 
yahshuatwo

GeneralRe: Another approachmemberradioman.lt11 Sep '08 - 7:55 
definitily yeah, virtual mode rocks && and gives ultimate control Big Grin | :-D
 
peace & serenity

QuestionRe: Another approach [modified]memberlumartineru5 Oct '08 - 11:35 
Hi,
I'm using your approach and I was able to update a row, but I need to identify in general if a row has been inserted, deleted or updated.
 
For now rows it seems I can use datagridview1.CurrentRow.IsNewRow.
 
Is there something like datagridview1.CurrentRow.ModificationType.
 
I also looked at datagridview.CurrentRow.State but does not apply, values are: displayed, frozen, none, readonly, resizible, etc.
 
Any help is really appreciated.
 
Regards
 
modified on Sunday, October 5, 2008 7:02 PM

GeneralRe: Another approachmemberg_g_1 Sep '09 - 19:08 
this is a great one around the old datgridview update. Also the orginal datagridview design was awful and vulnerable to error for updating to database.
 
there is a crude, easy to code approach for the vstd 2008 std edition or higher with dotnet 3.5 sp1.
 
If you don't need the ultimate control but just want to make sure the dgv contents get updated to the database, the change can also be quite simple, provided the followint is true:
 
- dgv is created form drag and drop a "table" from a strongly typed dataset "myDataset" created form sqlconnection in designer.
- the "table" in the the datset has been configured with direct database update capabilities
 
in formclosing event
one just need to
 
dgv.endEdit();
dgvBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.myDataset);
 
Crude but effective and quick. Like I said this is great for crude utility
of course one should have try clause around the aboae statements and handle the exception in a more friendly way, as well as be a bit more efficient by using the test
if (myDataset.HasChanges())....
 
G. G.
Thank you for your time and interests. Have a Wonderful day.

Generalbut if I have a querymembermhowin6 Nov '06 - 5:20 
in my project the datagridview is connected a one query.
When i try to update my tableAdaptare, i receive this error:
View or function 'MYQRY' is not updatable because the modification affects multiple base tables.
 
But my query is very simple!
If i launch the query in sqlserver, it works correctly.
 
can someone help me?
GeneralRe: but if I have a querymemberJohnieBraaf22 Mar '07 - 11:33 
U have to Update each Data Adapter for each table seperatly!
A data adapter can only contain 1 table, a dataset can contain multiple but cannot preform the update!
QuestionDatabase not getting UpdatedmemberJon Dwan20 Sep '06 - 1:35 
I have a created the auto saving function, everything appears to be working correctly however when i view the contents of the database table the changes have not be replciated to the database file. I have coded a VB version and checked it against the C# example and they appear to be the same - i have included my code below.
 
Any help on this one would be greatly appreciated.
 
---------------------------------------------------------------------------------------------
 
Imports System.Data.SqlClient
 
Public Class myOptions
 
Private Sub myOptions_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'ServicesDataSet.services' table. You can move, or remove it, as needed.
Me.ServicesTableAdapter.Fill(Me.ServicesDataSet.services)
End Sub
Private Sub myOptions_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
Me.updateServiceDataRow()
End Sub
 
Private servicesDataRow As DataRow = Nothing
 
Private Sub updateServiceDataRow()
If Me.servicesDataRow IsNot Nothing Then
If Me.servicesDataRow.RowState = DataRowState.Modified Then
Me.servicesDataRow.Item("updated_timestamp") = Date.Now
Me.servicesDataRow.Item("updated_user") = retrieveCurrentUser()
Me.ServicesTableAdapter.Update(Me.servicesDataRow)
Me.ServicesDataSet.Tables("services").AcceptChanges()
End If
End If
End Sub
Public Function retrieveCurrentUser() As String
Dim userName
Dim id As System.Security.Principal.WindowsIdentity = System.Security.Principal.WindowsIdentity.GetCurrent()
userName = id.Name.ToString
Return userName.Substring(userName.IndexOf("\") + 1, userName.ToString.Length - (userName.IndexOf("\") + 1))
End Function
 
Private Sub ServicesBindingSource_PositionChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ServicesBindingSource.PositionChanged
Dim thisBindingSource As BindingSource = CType(sender, BindingSource)
Dim thisDataRow As DataRow = CType(thisBindingSource.Current, DataRowView).Row
 
If thisDataRow.Equals(servicesDataRow) Then
Throw New ApplicationException("Position Changed Event was fired twice for the same row")
End If
 
Me.updateServiceDataRow()
Me.servicesDataRow = thisDataRow
End Sub
 
Private Sub btnNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNew.Click
Dim newRow As DataRow = Me.ServicesDataSet.Tables("services").NewRow
 
newRow("service_description") = ""
newRow("service_status") = 0
newRow("created_timestamp") = Date.Now
newRow("created_user") = retrieveCurrentUser()
 
Me.ServicesDataSet.Tables("services").Rows.Add(newRow)
 
End Sub
Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click
If Me.dgvServices.SelectedRows.Count = 0 Then
MessageBox.Show("Please select a record to remove.", "myScope", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Else
Dim selectedRows As DataGridViewSelectedRowCollection = Me.dgvServices.SelectedRows
Dim selectedRow As DataGridViewRow
 
For Each selectedRow In selectedRows
Me.ServicesDataSet.Tables("services").Rows(selectedRow.Index).Delete()
Next
 
Try
Me.ServicesTableAdapter.Update(Me.ServicesDataSet.Tables("services"))
Me.ServicesDataSet.Tables("services").AcceptChanges()
Catch ex As Exception
MessageBox.Show(ex.Message, "myScope", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Me.ServicesDataSet.RejectChanges()
End Try
End If
 
End Sub
End Class

AnswerRe: Database not getting UpdatedmemberC++reativeSoft22 Nov '06 - 9:45 
Right ! You have the same manifeste with binding textboxes and datagridview. No updates, no changes and no adding data for Access and sqlserver databases. Only Visual C++ 7.0 works FINE. So you have the choice. If not you have to workaround by other methodes. like shown in this forum.
C++reativeSoft
 
Only Visual C++ and C# dreams are allowed.

GeneralI did in an other waymemberinamgul20 Aug '06 - 21:34 
hello,
i incountered this problem and solved in another way.
 
I used the cell changed event in the datagrid and didn't care about whether the data in the cell is updated or not.
 
in my approach, for every move of cursor from one cell to another, i checked whether the new cell is in the current row or row is also changed.
as the following code illustrates.
private void dataGrid1_CurrentCellChanged(object sender, System.EventArgs e)
{
// If the row is changed, then save the data in the datagrid.
cellChanged();
}
 
and
 
void cellChanged()
{
if(prevCustRow!=dataGrid1.CurrentRowIndex)
{
prevCustRow = dataGrid1.CurrentRowIndex;
saveCust();
}
}
 
This has solved my problem.
GeneralNew record addmemberhominoid28 Jul '06 - 3:35 
This strategy doesn't work when I want to provide adding new records to grid...
GeneralThanks! And ... here's a class to encapsulate it.memberJeff Roush25 Jul '06 - 9:39 
I spent several hours yesterday struggling with how to do this. I saw the problems with handling several of the events mentioned above and in the comments before I ran across this article, but this article gave me the solution. Thanks!
 

In my application, I've got a number of DataGridViews that each need to be udpated. So I made a helper class, GridDataUpdater, to encapsulate the update functions.
 
This simplifies the code a lot when you've got more than one DataGridView, so I thought I'd pass it on.
 
To use it, you have to create a new instance of GridDataUpdater for each bound DataGridView. Then you tell that instance which TableAdapter update command to use when it updates the row of data, and also assign its two event handlers to the BindingSource's PositionChanged event and the DataGridView's Leave event:
 
private GridDataUpdater tableUpdater
...
 
private void initUpdateHandlers()
{
  tableUpdater = new GridDataUpdater();
  tableUpdater.TableUpdateCommand = new GridDataUpdater.TableUpdateCommandDelegate(tableAdapter.Update);
  theGridsBindingSource.PositionChanged += new EventHandler(tableUpdater.onBindingSource_PositionChanged);
  theDataGridView.Leave += new EventHandler(tableUpdater.onDataGridView_Leave);
}
 
The GridDataUpdater class itself is:
 
    public class GridDataUpdater
    {
        public delegate void TableUpdateCommandDelegate(System.Data.DataRow row);
        public TableUpdateCommandDelegate TableUpdateCommand;
 
        //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)
                {
                    TableUpdateCommand(LastDataRow);
                }
            }
        }
 
        private BindingSource thisBindingSource = null;
        public void onBindingSource_PositionChanged( object sender, EventArgs e)
        {
            // if the user moves to a new row, check if the last row was changed
            thisBindingSource = (BindingSource)sender;
            if (thisBindingSource.Current == null)
                return;
 
            DataRow ThisDataRow = ((DataRowView)thisBindingSource.Current).Row;
            if (ThisDataRow == LastDataRow)
                return;
 
            UpdateRowToDatabase();
            // track the current row for next PositionChanged event
            LastDataRow = ThisDataRow;
        }
 
        public void onDataGridView_Leave(object sender, EventArgs e)
        {
            if (thisBindingSource == null)
                return;
 
            DataGridView grid = (DataGridView)sender;
            if (grid.IsCurrentRowDirty)
            {
                grid.EndEdit();
                thisBindingSource.EndEdit();
                UpdateRowToDatabase();
            }
            LastDataRow = null;
        }
    }
 
 

GeneralRe: Thanks! And ... here's a class to encapsulate it.memberstuallenii28 Aug '06 - 9:11 
thanks for the helper class, I had to make a change to the delegate signature:
 
public class GridDataUpdater
{
public delegate int TableUpdateCommandDelegate(System.Data.DataRow row);

 
I would gather that most typed dataset generic update methods return an int.
GeneralIn addition to form's OnClose() event...memberDocX21 Jun '06 - 9:03 
Good point about checking for a final update before the form containing the grid closes, but users may also need to ensure that the most recent grid change gets recorded when keeping the form open, but clicking to other controls on the form. In this case, the grid's "Leave" event can be used, since it fires when the grid loses focus (i.e. when it is no longer the active control on the form).
GeneralRe: In addition to form's OnClose() event...memberJim Waverly14 Jul '06 - 8:25 
I found this article very useful!
 
While using the Leave event, I noticed that the binding is not always updated when the gridview is left. To resolve this, I used the following code. Obviously, some of your variables will be different.
 
    Private Sub dgvSources_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles dgvSources.Leave
        Dim Grid As DataGridView = sender
        If Grid.IsCurrentRowDirty Then
            Grid.EndEdit()
            HltSourceBindingSource.EndEdit()
            HltSourceTableAdapter.Update(HltSourceBindingSource.DataSource)
        End If
    End Sub

GeneralDataTable events can be used, I supposememberlponiew11 May '06 - 10:41 
but in handler body that handler must be temporarily uwired (using -= operator), DataTable updated then handler wired (+=) again - it works for me.
GeneralRe: DataTable events can be used, I supposememberfbachan22 Jun '06 - 1:04 
Could you please put the code for this? Thnaks
AnswerRe: DataTable events can be used, I supposememberddrinka28 Feb '07 - 20:34 
private DataRowChangeEventHandler _rowChangedEventHandler;
private DataRowChangeEventHandler _rowDeletedEventHandler;
 
public Form1()
{
     InitializeComponent();
     _rowChangedEventHandler=new DataRowChangeEventHandler(sgSmallGroup_RowChanged);
     _rowDeletedEventHandler=new DataRowChangeEventHandler(sgSmallGroup_RowDeleted);
}
 
private void Form1_Load(object sender, EventArgs e)
{
     RegisterChangeHandlers();
}
 
private void RegisterChangeHandlers()
{
     smallGroups.sgSmallGroup.RowChanged+=_rowChangedEventHandler;
     smallGroups.sgSmallGroup.RowDeleted+=_rowDeletedEventHandler;
}
 
private void UnregisterChangeHandlers()
{
     smallGroups.sgSmallGroup.RowChanged-=_rowChangedEventHandler;
     smallGroups.sgSmallGroup.RowDeleted-=_rowDeletedEventHandler;
}
 
void sgSmallGroup_RowDeleted(object sender, DataRowChangeEventArgs e)
{
     if(e.Row.RowState==DataRowState.Deleted)
     {
          UnregisterChangeHandlers();
          sgSmallGroupTableAdapter.Update(e.Row);
          RegisterChangeHandlers();
     }
}
 
void sgSmallGroup_RowChanged(object sender, DataRowChangeEventArgs e)
{
     if(e.Row.RowState==DataRowState.Modified||e.Row.RowState==DataRowState.Added)
     {
          UnregisterChangeHandlers();
          sgSmallGroupTableAdapter.Update(e.Row);
          RegisterChangeHandlers();
     }
}

GeneralDatagridView rotatememberhorvat9 May '06 - 19:57 
Is it possible to rotate datagridview by 90 degrees?
That means, is it possible to swap columns and rows in datagridview
 
Dejan
GeneralProblem while updatingmemberManish Jaiswal10 Apr '06 - 13:49 
Hi,
 
I coverted this code to vb.net and getting an error while updating the row at the follwoing line...
 
regionTableAdapter.Update(LastDataRow);
 
It says "value of type 'System.Data.DataRow' cannot be converted to '1-dimensional array of System.Data.DataRow'.
 
I'm passing a datarow as mentioned but the update function take 1-dimentional array of datarow as a parameter.
 
Any suggestions?
 
Thanks,

 
Manish Jaiwal
GeneralRe: Problem while updatingmemberCyrus Lesser22 Jul '06 - 0:11 
DataRow[] UpdateRows = { LastDataRow };
myAdapter.Update(UpdateRows);
 
That said, my update doesn't work for me. Seems it's not getting the data from the columns... but I'm a newb... I'm sure I'll work it out...
 
if (LastDataRow.RowState == DataRowState.Modified)
{
 
myAdapter.UpdateCommand = new MySqlCommand(
"UPDATE gul SET make = @make, model = @model ", conn);
// + "WHERE gulID = @gulID", conn);
 

param = myAdapter.UpdateCommand.Parameters.Add("@gulID", MySqlDbType.UInt64, 20);
param.SourceColumn = "gulID";
param.SourceVersion = DataRowVersion.Original;
 
param = myAdapter.UpdateCommand.Parameters.Add("@make", MySqlDbType.VarChar, 255);
param.SourceColumn = "make";
param.SourceVersion = DataRowVersion.Current;
 
param = myAdapter.UpdateCommand.Parameters.Add("@model", MySqlDbType.VarChar, 255);
param.SourceColumn = "model";
param.SourceVersion = DataRowVersion.Current;
 

DataRow[] UpdateRows = { LastDataRow };
myAdapter.Update(UpdateRows);
}

 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 26 Jan 2006
Article Copyright 2006 by Peter Huber SG
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid