Child Objects and Undo

Child Objects and Undo

Old forum URL: forums.lhotka.net/forums/t/12281.aspx


NikolasNick posted on Thursday, December 26, 2013

Hello,

I have an issue regarding child objects and undo. Undo doesn't work for child objects like:

 Public Shared ReadOnly VatRateProperty As PropertyInfo(Of VatRate) = RegisterProperty(Of VatRate)(Function(c) c.VatRate, RelationshipTypes.Child)

    Public Property VatRate() As VatRate
        Get
            Return GetProperty(VatRateProperty)
        End Get
        Set(ByVal value As VatRate)
            LoadProperty(VatRateProperty, value)
        End Set
    End Property

I'm assuming that the undo mechanism saves the reference of the object rather than the object itself. How can I overcome this problem?

 

p.s.: I'm not using the dataportal. I have my own classes for getting/saving data in mysql.

JonnyBee replied on Thursday, December 26, 2013

Hi,

That would depend on which type of object VatRate is. 

Basically - your object must implement ISupportUndo and the objects that support this is:

Undo saves the existing fielddata into a "stack" object graph - and you may even configure which serializer to use for Clone and N-level Undo. 

NikolasNick replied on Thursday, December 26, 2013

VatRate and all of my object inherits BusinessBase. When im calling CancelEdit of the BindingSource all the other strings and integers revert back to the their initial values but vatrate does not. Isn't this supposed to work if VatRate inherits BusinessBase or do i need to change the serializer?

JonnyBee replied on Friday, December 27, 2013

Are you using Windows Forms? 

You should never call BeginEdit/CancelEdit/ApplyEdit on an object that is active in databinding. The recommended approach is to call BeginEdit BEFORE you connect UI to Business Objects and when you want to cancel:

 

 

You may experience a situation where the user controls and the dataobjects is out-of -sync. Try to inspect the data field values after CancelEdit has been called. 

You must be aware of:

 

  1. Databinding will call BeginEdit/CancelEdit/ApplyEdit for every field as you tab around and/or edit value or cancel edit
  2. DataGridView will call BeginEdit/CancelEdit/ApplyEdit whenever you move from row to row (or press Esc to exit edit mode)

 

So your mindset should be that whenever a <bo> is active in databinding you should never call any of these methods. 

Also see: http://msdn.microsoft.com/en-us/library/system.componentmodel.ieditableobject.beginedit(v=vs.110).aspx
"
If BeginEdit is called on an object that is already being edited, the second and subsequent calls are ignored."

For CSLA this is implemented such that a <bo> knows whether IEditableObject.BeginEdit or ISupportUndo.BeginEdit and reacts according to specification after IEditableObject.BeginEdit has been called and until IEditableObject.CancelEdit or IEditableObject.EndEdit has been called.

NikolasNick replied on Friday, December 27, 2013

Yes I use winforms. I have tried and removed data binding from my object to ui completely (manually setting/getting values from controls) and still it doesn't work. I have even tried this and still doesn't work:

        Dim p As New Product  *Inherits BusinessBase(Of Product )

        Dim v1 As New VatRate  *Inherits BusinessBase(Of VatRate)
        v1.Id = 1
        p.VatRate = v1
        MsgBox(p.VatRate.Id)       ' prints 1

        p.BeginEdit()

        Dim v2 As New VatRate
        v2.Id = 5
        p.VatRate = v2
        MsgBox(p.VatRate.Id)        'prints 5

        p.CancelEdit()

        MsgBox(p.VatRate.Id)       ' again prints 5 BUT it should print 1?

JonnyBee replied on Friday, December 27, 2013

Well, that explains the whole issue.

The "snapshot" (ie statestack) is stored in a private member variable within each object  so you cannot assign a new object and the restore the old value.

 public abstract class UndoableBase : Csla.Core.BindableBase,  Csla.Core.IUndoableObject
 {

  // keep a stack of object state values.
  [NotUndoable()]
  private Stack<byte[]> _stateStack = new Stack<byte[]>();   // this is the snapshot

And also take into account that WindowsForms doesn't support/understand 1:1 relationship. 
So if you want references to a list - use the keyfield value rather than setting the item.
You should also understand the differences between 

These are discussed in Rockys Using Csla 4 : Creating Business Objects ebook.

I believe this should work tho';
        Dim p As New Product  *Inherits BusinessBase(Of Product )

        Dim v1 As New VatRate  *Inherits BusinessBase(Of VatRate)
        v1.Id = 1
        p.VatRate = v1
        MsgBox(p.VatRate.Id)       ' prints 1

        p.BeginEdit()

        Dim v2 As VatRate
v2 = v1.Clone()
        v2.Id = 5
        p.VatRate = v2
        MsgBox(p.VatRate.Id)        'prints 5

        p.CancelEdit()

        MsgBox(p.VatRate.Id)       ' again prints 5 BUT it should print 1?

NikolasNick replied on Friday, December 27, 2013

It's driving me crazy. I will attempt to modify the  "undo" functionality so that the state stack is not lost when assigning a new object rather than values to the object. Yes with your modification the example works but still not solving my issue... I want to assign new object rather than assign its values. Thanks for your time.

Copyright (c) Marimer LLC