Skip to content

EditLevelMismatch when cloning object #4794

@xal1983

Description

@xal1983

Describe the bug
When cloning an object graph that contains children, the edit level of the children is not correctly preserved.
Example scenario is Invoice with Cost line items. There is a BindingSource for the invoice and one for the child cost list.
Creating a clone and showing a new form with that cloned object triggers an EditLevelMismatch exception.

Version and Platform
CSLA version: 9.1.0
OS: Windows
Platform: WinForms

Code that Fails
I created a simple demo project to showcase the issue here: https://github.com/xal1983/CslaEditLevelMismatch/blob/master/EditLevelMismatch/Form1.cs

But the gist of it is, the child cost and it's field manager have an EditLevel = 1 at the time of cloning the invoice.
The cloned cost however ends up with EditLevel = 0 but it's FieldManager has an EditLevel = 1.
When setting the binding source, the binding source will automaticall call IEditableObject.BeginEdit() on the cost and Csla will raise the exception because the FieldManager and the Cost's EditLevels do not match.

Stack Trace or Exception Detail
at Csla.Core.FieldManager.FieldDataManager.Csla.Core.IUndoableObject.CopyState(Int32 parentEditLevel, Boolean parentBindingEdit) in //Source/Csla/Core/FieldManager/FieldDataManager.cs:line 512
at Csla.Core.UndoableBase.CopyState(Int32 parentEditLevel) in /
/Source/Csla/Core/UndoableBase.cs:line 167
at Csla.Core.BusinessBase.System.ComponentModel.IEditableObject.BeginEdit() in /_/Source/Csla/Core/BusinessBase.cs:line 778
at System.Windows.Forms.CurrencyManager.OnCurrentChanged(EventArgs e)
at System.Windows.Forms.CurrencyManager.ChangeRecordState(Int32 newPosition, Boolean validating, Boolean endCurrentEdit, Boolean firePositionChange, Boolean pullData)
at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
at System.Windows.Forms.BindingSource.OnListChanged(ListChangedEventArgs e)
at System.Windows.Forms.BindingSource.ResetBindings(Boolean metadataChanged)
at System.Windows.Forms.BindingSource.SetList(IList list, Boolean metaDataChanged, Boolean applySortAndFilter)
at System.Windows.Forms.BindingSource.ResetList()
at System.Windows.Forms.BindingSource.ParentCurrencyManager_MetaDataChanged(Object sender, EventArgs e)
at System.Windows.Forms.CurrencyManager.OnMetaDataChanged(EventArgs e)
at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
at System.Windows.Forms.BindingSource.OnListChanged(ListChangedEventArgs e)
at System.Windows.Forms.BindingSource.ResetBindings(Boolean metadataChanged)
at System.Windows.Forms.BindingSource.SetList(IList list, Boolean metaDataChanged, Boolean applySortAndFilter)
at System.Windows.Forms.BindingSource.ResetList()
at System.Windows.Forms.BindingSource.set_DataSource(Object value)
at EditLevelMismatch.Form1.SetDataSource(Invoice i) in E:\Devel\Tests\EditLevelMismatch\EditLevelMismatch\Form1.cs:line 27
at EditLevelMismatch.Form1.button1_Click(Object sender, EventArgs e) in E:\Devel\Tests\EditLevelMismatch\EditLevelMismatch\Form1.cs:line 46

Additional context
So, you may suggest "Call EndEdit or CancelEdit before cloning". however, this is precisely what I can't do. The use case is:
-User sees a list of invoices with the editor
-User start editing an invoice
-User needs to look up information from another invoice while editing the invoice
-At this point the app creates a clone of the in progress edit of the invoice and shows a popup with just the editor for this invoice, any edits being made so far need to be preserved, but the user needs to be able to cancel if they want to discard changes.

Metadata

Metadata

Labels

Type

Projects

Status

In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions