{"record":{"id":"61be4086be37f0b9","repo":"dotnet/wpf","slug":"unrecognized-stroke-in-stroke-invalidated-event-arguments","errorCode":null,"errorMessage":"Unrecognized Stroke in Stroke.Invalidated event arguments.","messagePattern":"Unrecognized Stroke in Stroke\\.Invalidated event arguments\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs","lineNumber":481,"sourceCode":"                {\n                    throw new System.ArgumentException(SR.UnknownStroke3);\n                }\n            }\n        }\n\n        /// <summary>\n        /// Stroke Invalidated event handler\n        /// </summary>\n        private void OnStrokeInvalidated(object sender, EventArgs eventArgs)\n        {\n            System.Diagnostics.Debug.Assert(_strokes.IndexOf(sender as Stroke) != -1);\n\n            // Find the visual associated with the changed stroke.\n            StrokeVisual visual;\n            Stroke stroke = (Stroke)sender;\n            if (!_visuals.TryGetValue(stroke, out visual))\n            {\n                throw new System.ArgumentException(SR.UnknownStroke1);\n            }\n\n            // The original value of IsHighligher and Color are cached in StrokeVisual.\n            // if (IsHighlighter value changed or (IsHighlighter == true and not changed and color changed)\n            // detach and re-attach the corresponding visual;\n            // otherwise Invalidate the corresponding StrokeVisual\n            if (visual.CachedIsHighlighter != stroke.DrawingAttributes.IsHighlighter ||\n                (stroke.DrawingAttributes.IsHighlighter &&\n                    StrokeRenderer.GetHighlighterColor(visual.CachedColor) != StrokeRenderer.GetHighlighterColor(stroke.DrawingAttributes.Color)))\n            {\n                // The change requires reparenting the visual in the tree.\n                DetachVisual(visual);\n                AttachVisual(visual, buildingStrokeCollection: false);\n\n                // Update the cached values\n                visual.CachedIsHighlighter = stroke.DrawingAttributes.IsHighlighter;\n                visual.CachedColor = stroke.DrawingAttributes.Color;\n            }","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs#L463-L499","documentation":"Renderer.OnStrokeInvalidated throws ArgumentException (SR.UnknownStroke1) when a Stroke.Invalidated event fires from a stroke that has no entry in the Renderer's _visuals map. The renderer caches a StrokeVisual per stroke; invalidated strokes must be ones it renders.","triggerScenarios":"Modifying a Stroke (points, drawing attributes) that is not attached to this Renderer — e.g. a stroke removed from the collection but still referenced, or a stroke shared across renderers where one renderer never tracked it.","commonSituations":"Retaining Stroke references after removing them from a StrokeCollection and mutating them later, sharing strokes between multiple InkCanvases/renderers, background thread mutations after detach.","solutions":["Stop holding/mutating Stroke references after removing them from the rendered collection","Attach strokes to only one Renderer at a time","Re-add the stroke to the StrokeCollection before mutating it if edits are intended","Guard mutations with a check that the stroke belongs to the live collection"],"exampleFix":"// before\nstroke.StylusPoints = newPoints; // stroke already removed from collection\n// after\nif (strokeCollection.Contains(stroke)) { stroke.StylusPoints = newPoints; }","handlingStrategy":"validation","validationCode":"// Only mutate strokes that are still in the rendered collection\nif (strokeCollection.Contains(stroke)) stroke.StylusPoints = newPoints;","typeGuard":"bool IsTrackedStroke(StrokeCollection c, Stroke s) => c?.Contains(s) == true;","tryCatchPattern":"try { stroke.StylusPoints = newPoints; }\ncatch (ArgumentException) { /* stroke no longer tracked - drop edit */ }","preventionTips":["Drop references to strokes once removed from the collection","Attach each stroke to at most one renderer at a time","Marshal stroke mutations to the UI thread","Avoid sharing Stroke instances across InkCanvas instances"],"tags":["ink","strokes","events","lifetime"],"backgroundTag":"entity-not-found","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"}