Vibrant discussion about CSLA .NET and using the framework to build great business applications.
Can anyone help me with this one please...?
I am using an EditableRootListBase object within a ( WinForms ) maintenance form as a container for a bunch of business objects. In fact the ERLB is used for binding the data entry fields, a grid, and an infragistics treeview which provides node level databinding. Obviously all are bound to a bindingsource which sits in between the UI and the ERLB list itself.
I can't seem to fathom how I undo changes if the user decides to abandon the changes they have made ?
My framework prevents the user navigating to another record if the data entered is invalid, so navigation is only possible once the data entered is valid.
I just can't fathom how to correctly undo any pending changes to the current row if the user decides to cancel the edit ? Obviously the current row could be a new row in which case it must be removed from the collection.
Any help would be most welcome!
Thanks in advance,
ERLB exists to address one very specific set of requirements: a list of root objects, bound to a datagrid, where changes to a row (object) are committed as soon as the user leaves that row.
Not to be too flippant, but any other use of ERLB is outside of its design parameters, and I wish people the best of luck making it work for their scenarios.
ERLB relies on the data binding contract used by datagrid controls (through IEditableObject) to know when to commit or cancel the edit of a given row (object). If you are using an ERLB outside of a datagrid control, you must completely emulate the datagrid model to get the desired behavior.
If you support remove and add operations things are a little more complex, as you need to emulate the datagrid behaviors for adding and removing items from the list as well.
Many thanks for your response.
I am using ERLB as a container for a list of root objects ( all pretty standard and based on BusinessBase ). Via the bindingsource, the list is bound to both a datagrid, and I also provide the usual set of text fields to assist in editing the data ( as the grid only shows some of the fields ).
Eveything has worked perfectly so far, I'm adding rows by using the AddNew() method of the bindingsource, and I can remove rows by using the RemoveAt(int index) method of the list itself. Again this works fine. The changes are committed by using the lists SaveItem() method. This however will be called directly when the user tries to navigate off the current record ( the Infragistics grid I'm using has a BeforeRowDeactivate() event, and its this I use to check if the current business object is dirty or savable ). Its just the undo where I have become stuck.
I think you are saying that I got lucky here, and that I should probably be using something based on BusinessListBase instead ?
Many thanks again.
The Infragistics datagrid should be just doing the right thing. You shouldn't have to manually worry about these details. As the user enters a row the grid should call BeginEdit, and as they leave the row it should call EndEdit, and if they press ESC it should call CancelEdit. All the mainstream datagrid controls work this way, so they are compatible with the Microsoft datagrid control (and therefore the DataTable, etc).
You should never interact with the list directly though. You should remove items via the bindingsource. In fact, all interactions should go through the bindingsource. Any direct interaction with the list object is asking for trouble. I wrote an entire chapter in the Using CSLA .NET 3.0 ebook which basically comes down to this one rule: if an object is data bound, only use the bindingsource for interaction.
The bindingsource always does the right thing - the thing ERLB is expecting. So if you call BeginEdit, EndEdit, CancelEdit, etc. via the bindingsource it should just do the right thing for you.
You shouldn't ever need to call SaveItem() explicitly. If you are using data binding correctly, the EndEdit call when a user leaves a row will automatically invoke SaveItem(). Similarly, the CancelEdit call when a user presses ESC will do the cancel, and automatically restart editing of the row.
Again - that's true as long as you are going through the bindingsource. If you interact with the list or the child object directly you are fighting data binding, and will almost certainly confuse the bindingsource (because it won't know what you did).
I have both your e-books, so I will have another read through them.
As always, your help is appreciated.
Sorry to be a pain here, but I have one final question.
Calling the bindingSource.RemoveCurrent() method works perfectly and deletes the object from the DB via the BO as required.
Calling the bindingSource.EndEdit() method also works perfectly and invokes the saving of data via the BO.
However, I am still slightly confused regarding the undo. Invoking the bindingSource.CancelEdit() method appears to work for the first undo and then fails for any subsequent undo's.
To make this work, I appear to have to grab the current object from the bindingsource and then invoke CancelEdit() on this directly. This also works perfectly, however I am not 100% sure this is what you meant ?
Am I still barking up the wrong tree !?
Calling bindingsource.CancelEdit() should just work. That'll cancel edits to the current object, and automatically immediately call BeginEdit() to put the object back into "edit mode". I would expect subsequent CancelEdit() calls to just repeat the process.
After some further playing around, you are of course right in that using a datagrid in conjunction with ERLB works fine providing you use the grid for manipulating the underlying data. I fully appreciate this is exactly what it is designed to do. What I can't appear to do easily is intercept the save or abandon process by throwing a dialog which asks the user if they want to save or abandon the changes first. This is really what I'm after.
All I'm really trying to achieve is to provide a simple way of navigating through a bunch of root BO's within a maintenance form. The contents of the list are selected randomly by the user depending on what they choose to look at. They are not child objects selected by a single select command.
Currently I have a seperate list object which provides the navigation list ( associated with a bindingsource ), and any movement on here instantiates the appropriate BO to permit editing ( via a second bindingsource ). I then use your methodology ( the one you didn't include in the e-book ) to update the navigation list when the BO is modified and subsequently saved.
This does work fine, however I felt having a seperate list and list object just to provide navigation for each form is a bit clunky. In effect every maintenance form needs its own set of navigation objects, and this starts to mount up when you have a lot of maintenance forms in your application.
Surely a simple list holding a bunch of business objects would be much better, but going this route seems to make it difficult to intercept the save and abandon process inherent with databinding.
I guess I just want to make sure my logic is correct before heading off to write a hundred maintenance forms which then all turn out to be flawed!
As always, any comment is welcome!
You should know that you don't have to use BLB or ERLB if they don't fit your needs. You can use any serializable list type, and add your own behaviors to that type as needed. You might use BLB or ERLB as a guide to get ideas on how to address certain problems, etc. It might be better for you to create your own, simpler, list type.
Fwiw, in CSLA 4 it is possible to bind an object to multiple bindingsource controls (our one Windows Forms enhancement), which might simplify you implementation.