{"record":{"id":"9011851da990e20c","repo":"dotnet/wpf","slug":"duplicate-stroke-in-strokecollectionchangedeventargs-added","errorCode":null,"errorMessage":"Duplicate Stroke in StrokeCollectionChangedEventArgs.Added.","messagePattern":"Duplicate Stroke in StrokeCollectionChangedEventArgs\\.Added\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs","lineNumber":436,"sourceCode":"\n        /// <summary>\n        /// StrokeCollectionChanged event handler\n        /// </summary>\n        private void OnStrokesChanged(object sender, StrokeCollectionChangedEventArgs eventArgs)\n        {\n            System.Diagnostics.Debug.Assert(sender == _strokes);\n\n            // Read the args\n            StrokeCollection added = eventArgs.Added;\n            StrokeCollection removed = eventArgs.Removed;\n\n            // Add new strokes\n            foreach (Stroke stroke in added)\n            {\n                // Verify that it's not a dupe\n                if (_visuals.ContainsKey(stroke))\n                {\n                    throw new System.ArgumentException(SR.DuplicateStrokeAdded);\n                }\n\n                // Create a visual for the new stroke and add it to the dictionary\n                StrokeVisual visual = new StrokeVisual(stroke, this);\n                _visuals.Add(stroke, visual);\n\n                // Start listening on the stroke events\n                StartListeningOnStrokeEvents(visual.Stroke);\n\n                // Attach it to the visual tree\n                AttachVisual(visual, buildingStrokeCollection: false);\n            }\n\n            // Deal with removed strokes first\n            foreach (Stroke stroke in removed)\n            {\n                // Verify that the event is in sync with the view\n                StrokeVisual visual = null;","sourceCodeStart":418,"sourceCodeEnd":454,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs#L418-L454","documentation":"Renderer.OnStrokesChanged throws ArgumentException (SR.DuplicateStrokeAdded) when a StrokeCollectionChangedEventArgs reports a stroke in its Added collection that the Renderer already tracks in its stroke-to-visual map. Each stroke must map to exactly one StrokeVisual.","triggerScenarios":"Adding the same Stroke instance twice to a StrokeCollection, or sharing one Stroke instance across multiple StrokeCollections wired to the same Renderer/InkCanvas.","commonSituations":"Cloning strokes by reference instead of deep copy, moving strokes between collections by Add without Remove, event handler re-entrancy replaying an add notification.","solutions":["Never add the same Stroke instance twice to a StrokeCollection","Deep-copy or clone strokes when moving between collections","Remove the stroke from the old collection before adding to a new one","Check StrokeCollection.Contains before Add in custom code"],"exampleFix":"// before\nanotherCollection.Add(stroke); // stroke still in firstCollection\n// after\nfirstCollection.Remove(stroke);\nanotherCollection.Add(new Stroke(stroke.StylusPoints.Clone()));","handlingStrategy":"validation","validationCode":"// Avoid duplicate adds\nif (!collection.Contains(stroke)) collection.Add(stroke);","typeGuard":"bool CanAddSafely(StrokeCollection c, Stroke s) => s != null && !c.Contains(s);","tryCatchPattern":"try { collection.Add(stroke); }\ncatch (ArgumentException) { /* duplicate - ignore or log */ }","preventionTips":["Never Add a Stroke instance already in the collection","Clone strokes when transferring between collections","Route all collection mutations through one owner","Beware re-entrant event handlers replaying Adds"],"tags":["ink","strokes","duplicate","events"],"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"}