{"record":{"id":"9e6c11cb9b4e32a7","repo":"dotnet/wpf","slug":"sr-enumerator-collectionchanged-model3dcollection","errorCode":null,"errorMessage":"SR.Enumerator_CollectionChanged","messagePattern":"SR\\.Enumerator_CollectionChanged","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Model3DCollection.cs","lineNumber":830,"sourceCode":"            {\n                _list.ReadPreamble();\n\n                if (_version == _list._version)\n                {\n                    if (_index > -2 && _index < _list._collection.Count - 1)\n                    {\n                        _current = _list._collection[++_index];\n                        return true;\n                    }\n                    else\n                    {\n                        _index = -2; // -2 indicates \"past the end\"\n                        return false;\n                    }\n                }\n                else\n                {\n                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);\n                }\n            }\n\n            /// <summary>\n            /// Sets the enumerator to its initial position, which is before the\n            /// first element in the collection.\n            /// </summary>\n            public void Reset()\n            {\n                _list.ReadPreamble();\n\n                if (_version == _list._version)\n                {\n                    _index = -1;\n                }\n                else\n                {\n                    throw new InvalidOperationException(SR.Enumerator_CollectionChanged);","sourceCodeStart":812,"sourceCodeEnd":848,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media3D/Generated/Model3DCollection.cs#L812-L848","documentation":"Model3DCollection's strongly-typed enumerator throws InvalidOperationException(SR.Enumerator_CollectionChanged) from MoveNext when the collection's version counter changed since enumeration started. WPF enumerators are fail-fast: any Add/Remove/Insert during a foreach invalidates the enumerator. The _index == -2 sentinel indicates past-the-end state handled separately; this throw is the mid-enumeration mutation case.","triggerScenarios":"Modifying the Model3DCollection (Add, Remove, Insert, Clear, indexer set) between MoveNext calls inside a foreach or while advancing the enumerator manually.","commonSituations":"Removing a model from the collection in response to a property change triggered while iterating; UI-event handlers mutating the collection during enumeration; background threads touching the collection while the UI thread enumerates.","solutions":["Snapshot before iterating: foreach (var m in collection.ToArray()) so mutation of the original is safe.","Collect items to remove/add in a temporary list, then apply the changes after the loop.","If multithreaded, marshal all collection mutations to the UI (dispatcher) thread and never enumerate while another thread mutates."],"exampleFix":"// before\nforeach (var m in collection)\n{\n    if (ShouldRemove(m)) collection.Remove(m); // InvalidOperationException\n}\n// after\nforeach (var m in collection.ToArray())\n{\n    if (ShouldRemove(m)) collection.Remove(m);\n}","handlingStrategy":"try-catch","validationCode":"int v0 = collection.Count; // capture; if you cannot guarantee no mutation, snapshot\nvar snapshot = collection.ToArray();","typeGuard":null,"tryCatchPattern":"try { foreach (var m in collection) { /* ... */ } } catch (InvalidOperationException ex) when (ex.Message.Contains(\"CollectionChanged\")) { // retry with a snapshot\n    foreach (var m in collection.ToArray()) { /* ... */ } }","preventionTips":["Never mutate a WPF collection while enumerating it","Buffer changes in a temp list and apply after the loop","Use ToArray() snapshots when handlers may mutate the collection","Keep collection access single-threaded (UI thread)"],"tags":["wpf","collection","enumerator","concurrency"],"backgroundTag":"invalid-state-transition","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}