- Home
- LLBLGen Pro
- LLBLGen Pro Runtime Framework
Databinding, new entities and events
Joined: 05-Apr-2005
Hi Otis,
I noticed the following: when I add an entity to a collection via databinding and change some field values, the collection's ListChanged event is only called after the CurrencyManager changes its position to another entity (because that in turn calls CancelEdit(), I presume). However, if I do the same with existing entities, the event is raised immediately after the field change.
I checked the (your) source code, and I guess it's due to these lines in EntityBase2.SetNewFieldValue():
if(valueIsSet)
{
if((!_editCycleInProgress)||(_editCycleInProgress && !_isNew)||(_editCycleInProgress && _parentCollection==null))
{
// fire the EntityContentsChanged event, if there are subscribers.
FlagMeAsChanged();
}
else
{
// edit cycle in progress, hold the signal till endedit is called
_pendingChangedEvent = true;
}
}
I wonder why you defer the event if the entity is new, because in a datagrid, for instance, the fields are not updated if the new entity is changed outside the grid. If the entity is not new, they are updated. So it occurs a bit inconsistent to me. Anyway, I wouldn't have noticed that. But I'm databinding to a treeview (and it finally works, except this one thing), and when a new entity is added, the user should be able to change the display member outside the treeview, and the change should IMHO be visible at once.
Any thoughts on this one? Regards Stefan
TheSwiss wrote:
Hi Otis,
I noticed the following: when I add an entity to a collection via databinding and change some field values, the collection's ListChanged event is only called after the CurrencyManager changes its position to another entity (because that in turn calls CancelEdit(), I presume).
No, EndEdit . CancelEdit is called when ESC is pressed.
However, if I do the same with existing entities, the event is raised immediately after the field change.
I checked the (your) source code, and I guess it's due to these lines in EntityBase2.SetNewFieldValue():
if(valueIsSet) { if((!_editCycleInProgress)||(_editCycleInProgress && !_isNew)||(_editCycleInProgress && _parentCollection==null)) { // fire the EntityContentsChanged event, if there are subscribers. FlagMeAsChanged(); } else { // edit cycle in progress, hold the signal till endedit is called _pendingChangedEvent = true; } }
I wonder why you defer the event if the entity is new, because in a datagrid, for instance, the fields are not updated if the new entity is changed outside the grid. If the entity is not new, they are updated. So it occurs a bit inconsistent to me. Anyway, I wouldn't have noticed that. But I'm databinding to a treeview (and it finally works, except this one thing), and when a new entity is added, the user should be able to change the display member outside the treeview, and the change should IMHO be visible at once.
Any thoughts on this one? Regards Stefan
The change event is postponed till EndEdit is called, because if the user changes a cell, then presses ESC, no change happens, so you don't want a changed event to be fired, because that could trigger expensive code or flags which aren't reset later on.
If the control doesn't support IEditableObject, there is no edit cycle in progress, and thus also no rollback of changed values via ESC, the changed event is given immediately.
Joined: 05-Apr-2005
Otis wrote:
TheSwiss wrote:
Hi Otis,
I noticed the following: when I add an entity to a collection via databinding and change some field values, the collection's ListChanged event is only called after the CurrencyManager changes its position to another entity (because that in turn calls CancelEdit(), I presume).
No, EndEdit
. CancelEdit is called when ESC is pressed.
Of course. That's what I actually meant.
Otis wrote:
The change event is postponed till EndEdit is called, because if the user changes a cell, then presses ESC, no change happens, so you don't want a changed event to be fired, because that could trigger expensive code or flags which aren't reset later on.
If the control doesn't support IEditableObject, there is no edit cycle in progress, and thus also no rollback of changed values via ESC, the changed event is given immediately.
That's what I initially suspected, but why the inconsistency between new, but modified, entities and fetched entities?
An edit cycle on a row in a grid has two phases: first the row enters the edit cycle and then each cell which is visited enters its own edit cycle (which is ended when teh cell is left or esc is pressed).
WHen an entity is new in a bound collection, the entity is likely added through the grid's call to IBindingList.AddNew.
Though, when the user fills in all cells and at the end presses ESC twice, it will rollback the last cell, but ALSO remove the entity. As if there wasn't any new entity at all. At that point there isn't any change. As I don't know if the editcycle started when the user re-entered a new entity or when it edits a just added new entity, I can't decide what to do, so I leave the events till the new entity is really accepted as a new entity.
(edit): I can of course introduce some flags to track all this. The problem with databinding and IEditableObject is that some grids call BeginEdit/EndEdit more times than others... It's all in all a very frustrating experience and lots of silly code in BeginEdit/EndEdit for example if there's already a cycle going on or not... also if you enter a row, BeginEdit is called on some grids, not on all. (as edit hasn't started yet!).
Joined: 05-Apr-2005
Otis wrote:
Though, when the user fills in all cells and at the end presses ESC twice, it will rollback the last cell, but ALSO remove the entity. As if there wasn't any new entity at all. At that point there isn't any change. As I don't know if the editcycle started when the user re-entered a new entity or when it edits a just added new entity, I can't decide what to do, so I leave the events till the new entity is really accepted as a new entity.
As far as I understand your source code, you're in fact tracking it with _isNewViaDataBinding, which, to my perception, is only TRUE in the first edit cycle. Then again, ...
Otis wrote:
The problem with databinding and IEditableObject is that some grids call BeginEdit/EndEdit more times than others... It's all in all a very frustrating experience and lots of silly code in BeginEdit/EndEdit for example if there's already a cycle going on or not... also if you enter a row, BeginEdit is called on some grids, not on all. (as edit hasn't started yet!).
... that IS a problem
So some grids "kill" the _isNewViaDataBinding flag, so that an entity added via databinding is not _isNewViaDataBinding any more before it can effectively be edited?!? Arrrrgh... Wouldn't it help to set _isNewViaDataBinding to false in EndEdit() if (and only if) at least one field has been changed in the cycle? That would avoid setting it to false just by calling BeginEdit() and EndEdit() immediately afterwards. And if so, you could use that flag in order to track
Otis wrote:
if the editcycle started when the user re-entered a new entity or when it edits a just added new entity
which would in turn solve/make possible the rest, if I got you right (and if I understood the respective parts of your code correctly).
Would the above be an option?
TheSwiss wrote:
Otis wrote:
Though, when the user fills in all cells and at the end presses ESC twice, it will rollback the last cell, but ALSO remove the entity. As if there wasn't any new entity at all. At that point there isn't any change. As I don't know if the editcycle started when the user re-entered a new entity or when it edits a just added new entity, I can't decide what to do, so I leave the events till the new entity is really accepted as a new entity.
As far as I understand your source code, you're in fact tracking it with _isNewViaDataBinding, which, to my perception, is only TRUE in the first edit cycle. Then again, ...
Otis wrote:
The problem with databinding and IEditableObject is that some grids call BeginEdit/EndEdit more times than others... It's all in all a very frustrating experience and lots of silly code in BeginEdit/EndEdit for example if there's already a cycle going on or not... also if you enter a row, BeginEdit is called on some grids, not on all. (as edit hasn't started yet!).
... that IS a problem
![]()
![]()
So some grids "kill" the _isNewViaDataBinding flag, so that an entity added via databinding is not _isNewViaDataBinding any more before it can effectively be edited?!? Arrrrgh... Wouldn't it help to set _isNewViaDataBinding to false in EndEdit() if (and only if) at least one field has been changed in the cycle? That would avoid setting it to false just by calling BeginEdit() and EndEdit() immediately afterwards. And if so, you could use that flag in order to track
Otis wrote:
if the editcycle started when the user re-entered a new entity or when it edits a just added new entity
which would in turn solve/make possible the rest, if I got you right (and if I understood the respective parts of your code correctly). Would the above be an option?
Could be, I've to test. Writing that code was very frustrating and is a pure result of trial/error. There is no real documentation what to expect really, it already was a surprise to me that BeginEdit was called twice on the ENTITY when you click a cell. Once for the entity and once for the field. Which IMHO was pretty stupid as the second BeginEdit should be called on the field, not on the entity. Though you then see the dataset core of it all...
Setting isNewViaDataBinding to false only if a cell has been changed could mess with a cancel edit. The second time a user enters the row, presses ESC twice, the row vanishes!