Fix EditLevelMismatch when cloning object graphs during edit sessions#4821
Merged
rockfordlhotka merged 5 commits intomainfrom Feb 14, 2026
Merged
Fix EditLevelMismatch when cloning object graphs during edit sessions#4821rockfordlhotka merged 5 commits intomainfrom
rockfordlhotka merged 5 commits intomainfrom
Conversation
Co-authored-by: rockfordlhotka <2333134+rockfordlhotka@users.noreply.github.com>
Co-authored-by: rockfordlhotka <2333134+rockfordlhotka@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix EditLevelMismatch when cloning object graph
Fix EditLevelMismatch when cloning object graphs during edit sessions
Feb 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Ports fix from v9.x branch (PR #4796). Cloning object graphs with children during active edit sessions threw
EditLevelMismatchexceptions becauseInsertItemcalledResetChildEditLevelduring deserialization, forcing child edit levels to 0 despite being correctly deserialized with their original edit levels.Changes
BusinessBindingListBase.cs & BusinessListBase.cs
_isDeserializingflag (NonSerialized, NotUndoable)OnSetChildrenduring deserialization (try-finally block)ResetChildEditLevelandEditLevelAddedassignment inInsertItemwhen deserializingBusinessListBaseTests.cs
Example
Enables clone-then-edit workflows where users inspect/modify clones in separate views while maintaining undo capability on both original and clone.
Original prompt
This section details on the original issue you should resolve
<issue_title>EditLevelMismatch when cloning object</issue_title>
<issue_description>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.
</issue_description>
<agent_instructions>I fixed this in the v9.x branch already. The goal now is to take those same fixes and apply them to the main branch.</agent_instructions>
Comments on the Issue (you are @copilot in this section)
@rockfordlhotka @xal1983 I'm not 100% sure this is a supported scenario.You are in the middle of editing an object graph, so various edit levels within the graph could be all over the place. And you clone the graph, so those edit levels could stay the same - but unless you can figure out the exact edit states of the whole graph how would you bind the clone to a UI? Or do anything else with it in such an indeterminate state?
@xal1983 Hi @rockfordlhotka, I'm not sure why this wouldn't be supported, this app has been relying on this behavior for 20 years (migrating from Csla 4 to 9 atm), it's possible it works because when the BeginEdit is called from a BindingSource it only ever gets to level 1 because of the special handling for System.ComponentModel.IEditableObject. Regardless, the fact is ...💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.