Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm Data Binding / February 2006

Tip: Looking for answers? Try searching our database.

Detecting changes to data

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Jim H - 13 Feb 2006 19:11 GMT
What is the proper way to indicate that changes have been made to data on a form so
that an Update method can be called when the Form closes, if and only if, there have
been changes made to the data by the user.

I started with the Walkthrough: Displaying Data in a Windows Form Using a Parameterized Query.
Suggested Next Step: Add buttons that let the user add, edit and delete authors.

This code uses bound textBoxes, v1.1 of the Framework.

I added the following functionality to the Form_Closing event:

private void Form1_Closing( object sender, System.ComponentModel.CancelEventArgs e )
{
  if ( dsAuthors1.HasChanges() )
  {
     oleDbDataAdapter1.Update( dsAuthors1 );
  }
}

This works if the user moves off the Row that was changed (forwards or backwards).  But,
if the user loads the DataSet, changes one of the TextBoxes, and then closes the Form
without navigating to a different row, the changes are not presisted to the database.
In other words, the HasChanges appears to not be set even through there was a change
made to the bound data in one of the textBoxes.

It is not acceptable to require a user to move to a different row.  I do not want to
call Update if there are no changes.  And, I would like to avoid having an explicit
"Edit" Button on the form.  I want an implied "Edit and Update" if the user changes any
data on any row and then immediately closes the form.  

Is it going to be necessary to trap an event for every control that allows data to be
changed.  If so, would a loop at Form_Closing() be the right approach, like so:

  foreach ( Control oControl in this.Controls )
  {
      if (?)                 // Check some property of Control
         isDirty = true;     // May have to select Types of Controls with GetType()
  }

  if ( isDirty || dsAuthors1.HasChanges() )
  {
     oleDbDataAdapter1.Update( dsAuthors1 );
  }

Is an Event Handler going to have to be coded for each TextBox to handle some Event that
fires when the USER has changed the data, and only when the User has changed the data --
I don't need an event that fires when the DataSouce changes it.  Is it going to be
necessary to trap keystrokes for each textBox?

Jim Holloman
Bart Mermuys - 14 Feb 2006 12:38 GMT
Hi,

> What is the proper way to indicate that changes have been made to data on
> a form so
[quoted text clipped - 62 lines]
> going to be
> necessary to trap keystrokes for each textBox?

I can't tell you what best to do, because i haven't figured it out myself.

1. Detecting whether there is a change is difficult, in NET2.0, you can do
something like:

Validate();  // missing in NET1.1
if (
((DataRowView)bindingSource.Current).Row.HasVersion(DataRowVersion.Proposed))
{
   // changes were made to the current row
}

2. Calling CurencyManager.EndCurrentEdit() results in two things :
- the last changed value will be persisted if it didn't because Validating
didn't fire on the last Control (replaced with Validate() in NET2.0)
- the underlying DataRow will change its RowState (so an update will work).

eg.
BindingContext[DataSource, DataPath].EndCurrentEdit();

Problem:  EndCurrentEdit() may throw if there is a ConstraintError.

So the problem is that it's not just saving but also ending edit.

HTH,
Greetings

> Jim Holloman
Jim H - 15 Feb 2006 21:39 GMT
Thanks, Bart, that is what I was seeking.

I have a lot to learn about BindingManager, CurrencyManager, PropertyManager, and DataBinding.

In my case, the EndCurrentEdit didn't throw a Constraint Exception; most likely because I used the
defaults when Filling the DataSet and thus didn't transfer the Constraints from the Database to the
DataSet.  However, the Update to the Database did throw an Constraint Exception.  I trapped it as
shown below.  I placed a 'Apply Changes' Button on the Form that will allow the user to post any
changes made back to the Database at will.  Then, if there are a number of changes, the user can
make a few, apply them, make a few more, apply them, and so on.

QUESTION: Do you generally recommend loading all the schema into a DataSet -- or do you generally
use the very limited schema provided by default when doing a Fill?

MY CODE (THAT SEEMS TO WORK):

     /*******************************************************************************************
     @Closing of Form1()
     *******************************************************************************************/
     private void Form1_Closing( object sender, System.ComponentModel.CancelEventArgs e )
     {
       
        try
        {
           BindingContext[dsAuthors1, "authors"].EndCurrentEdit();
        }  
        catch ( Exception Excpt )
        {
           MessageBox.Show( "Error: \n" + Excpt.Message );
        }

        // MessageBox -- Save changes to data (Y-N)?
        // Does the user want to apply changes to the Database?
        if ( dsAuthors1.HasChanges() )
        {
           if ( DialogResult.Yes == MessageBox.Show( Form1.ActiveForm,
                   "Save changes to data?",
                   "Exiting",
                   MessageBoxButtons.YesNo,
                   MessageBoxIcon.Question ) )
           {
              applyChanges();  // Invokes oleDbDataAdapter1.Update( dsAuthors1 ) to post
                               // changes to the Db
           }
        }

     }

     /******************************************************************************************
     @ApplyChanges() -- Sends all changes in the DataSet back to the Database via
                        DataAdapter Update().                                  
     *******************************************************************************************/      
     private void applyChanges()
     {
        if ( dsAuthors1.HasChanges() )
        {
           // Improvement: Need to get only changesto the Dataset with GetChanges() and use
           // them rather than the complete DataSet
           try
           {
              oleDbDataAdapter1.Update( dsAuthors1 );
           }  
           catch ( Exception Excpt )
           {
              MessageBox.Show( "ERROR: \n"                           +
                               "Update of authors table failed. \n"  +
                               "All changes made since the last 'Apply Changes' will be discarded.                          
                                \n\n" +
                               Excpt.Message );
           }

           try
           {
              dsAuthors1.AcceptChanges();  // Tell the DataSet to Update itself by applying
                                           // all changes
           }  
           catch ( Exception Excpt )
           {
              MessageBox.Show( "Error on dsAuthors1.AcceptChanges(): \n" + Excpt.Message );
           }
        }
     }
Bart Mermuys - 16 Feb 2006 15:30 GMT
Hi,

> Thanks, Bart, that is what I was seeking.
>
[quoted text clipped - 16 lines]
> DataSet -- or do you generally
> use the very limited schema provided by default when doing a Fill?

In NET1.1 i mostly used untyped DataSet's, schema loaded by a Fill.  But in
NET2.0 there is a new concept of Data Sources (note the space).  A project
can have a number of Data Source's ( *typed* DataSets, custom lists or
objects).

DataAdapter.Update may throw an exception and then it won't save other
pending changes, so you could also set DataAdapter.ContinueUpdateOnError to
true and then check DataTable.GetErrors/DataTable.HasErrors afterwards.

You almost never have to call AcceptChanges yourself, in your example you
don't need to call AcceptChanges since Update will do that for each row that
was succesfully saved.

And only updating the changed rows won't provide much improvement over
updating the entire DataTable (it can even cause more problems if you use
autonumbers.) In the end both methods need to find the rows that have
changed.  (The DataAdapter won't update a row that didn't changed).

HTH,
Greetings

THAT SEEMS TO WORK):

> /*******************************************************************************************
>      @Closing of Form1()
[quoted text clipped - 71 lines]
>         }
>      }

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.