Editing data in Delphi controls and updating of its underlying dataset

2.4k views Asked by At

In embarcadero docwiki, it says:

In all data controls except TDBGrid, when you modify a field, the modification is copied to the underlying dataset when you Tab from the control. If you press Esc before you Tab from a field, the data control abandons the modifications, and the value of the field reverts to the value it held before any modifications were made. In Vcl.DBGrids.TDBGrid, modifications are posted when you move to a different record

I'm working using TDBGrid (amongst other data controls) and I find his updating behavior to be profoundly unnatural. I would expect the updating being made when the user hits "ENTER", not only when the user "moves to a different record" or "Tab from the control".

My question is how could I change this? Any ideas?

Thank you in advance.

2

There are 2 answers

0
MartynA On BEST ANSWER

I think you might be confusing two things, namely changes being relayed back from DB-aware controls such as TDBEdits to the corresponding dataset TFields objects of the dataset, and changes in the field values being posted back from the fields to the dataset's database data.

That's partly why I suggested in a comment that you should add a TDBNavigator to your form. Connected to the same DataSource as your DB-aware controls, it will show the state of the DataSet by enabling its Save and Cancel buttons when the DataSet has been put into an editing state, as happens when the user changes the contents of one of the controls. Incidentally, this change of state only happens if the DataSource's AutoEdit property is set to True (which it is by default, so it's easy to miss what's going on and not realise that you can prevent it if you want).

The reason that the TDBGrid is a bit different is as follows:

  • The TDataSet behind it is designed to have a logical cursor which can be moved from record to record but can only access one record at a time - the associated TFields contain the data values of the record the cursor is currently on.

  • Therefore the DBGrid has to be populated by scrolling the dataset cursor.

  • Normally, the DataSet is in dsBrowse state (see TDataSetState in OLH). When it is told to scroll, if its current state is dsEdit or dsInsert (e.g. because of user action in the GUI), it posts any changes to the current record back to the dataset, and reverts to dsBrowse state so that it can scroll as instructed.

  • This post-before-scroll behaviour doesn't sit v. happily with the fact that the DBGrid provides GUI access to a number of records "simultaneously" from the user's pov. Because, as you have noticed, the user may change one record (by in-place editing in the grid or via DBEdits, etc) and immediately move to another row. In fact, your best option so far as editing in-place in the grid is concerned is often simply not to allow it - because otherwise the user can change something in one record and then accidentally or on purpose click on another grid row, which posts the change in the previous row to the dataset without giving the user the opportunity to cancel it.

IMO, you shouldn't leave it to OnExit handlers, focus-change events, etc, to do operations on the dataset - it's fine to use them to prevent the user closing the form with data changes pending and similar things, but you ought to require the user to perform an explicit action to determine whether to save or cancel pending changes. One reason not to attempt operations directly on the dataset from OnExit, etc, is that often it's necessary to perform data-validation checks in the GUI on data changed/added by the user, and that may in itself require focus changes to guide the user through any corrective action necessary.

1
penarthur66 On

Add a Post statement to the OnExit of the Grid?

I always put a series of Post statement in my OnFormCloseQuery events too.