{"record":{"id":"dc3cccd32826a556","repo":"dotnet/wpf","slug":"cannot-attach-a-visual-that-is-already-attached","errorCode":null,"errorMessage":"Cannot attach a Visual that is already attached.","messagePattern":"Cannot attach a Visual that is already attached\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs","lineNumber":289,"sourceCode":"        /// <param name=\"drawingAttributes\">drawing attributes that used in the incremental rendering</param>\n        internal void AttachIncrementalRendering(Visual visual, DrawingAttributes drawingAttributes)\n        {\n            // Check the input parameters\n            ArgumentNullException.ThrowIfNull(visual);\n            ArgumentNullException.ThrowIfNull(drawingAttributes);\n\n            //harden against eaten exceptions\n            bool exceptionRaised = false;\n\n            // Verify that the visual hasn't been attached already\n            if (_attachedVisuals != null)\n            {\n                foreach(Visual alreadyAttachedVisual in _attachedVisuals)\n                {\n                    if (visual == alreadyAttachedVisual)\n                    {\n                        exceptionRaised = true;\n                        throw new System.InvalidOperationException(SR.CannotAttachVisualTwice);\n                    }\n                }\n            }\n            else\n            {\n                // Create the list to register attached visuals in\n                _attachedVisuals = new List<Visual>();\n            }\n\n\n            if (!exceptionRaised)\n            {\n                // The position of the visual in the tree depends on the drawingAttributes\n                // Find the appropriate parent visual to attach this visual to.\n                ContainerVisual parent = drawingAttributes.IsHighlighter ? GetContainerVisual(drawingAttributes) : _incrementalRenderingVisuals;\n\n                // Attach the visual to the tree\n                parent.Children.Add(visual);","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs#L271-L307","documentation":"Renderer.AttachIncrementalRendering throws InvalidOperationException (SR.CannotAttachVisualTwice) when the same Visual is attached more than once. The Renderer keeps a list of attached visuals to prevent duplicate registration for incremental ink rendering.","triggerScenarios":"Calling AttachIncrementalRendering twice with the same visual, or attaching a visual already attached through another InkPresenter/Renderer sharing it.","commonSituations":"Re-initializing an InkCanvas/dynamic renderer without detaching first, attaching the same host visual to multiple renderers, event handler re-entrancy causing double attach.","solutions":["Track attach state and only call AttachIncrementalRendering if not already attached","Call DetachIncrementalRendering before re-attaching the visual","Ensure each Renderer gets its own host visual","Guard with a try-catch or a Contains check on your own attached-visual bookkeeping"],"exampleFix":"// before\nrenderer.AttachIncrementalRendering(hostVisual, constraints); // may run twice\n// after\nif (!attached.Contains(hostVisual))\n{\n    renderer.AttachIncrementalRendering(hostVisual, constraints);\n    attached.Add(hostVisual);\n}","handlingStrategy":"validation","validationCode":"// Track attached visuals yourself\nbool alreadyAttached = attachedVisuals.Contains(hostVisual);\nif (!alreadyAttached) renderer.AttachIncrementalRendering(hostVisual, strokers);","typeGuard":"bool CanAttach(Renderer r, Visual v) => v != null && !attachedVisuals.Contains(v);","tryCatchPattern":"try { renderer.AttachIncrementalRendering(visual, strokers); }\ncatch (InvalidOperationException) { /* already attached - skip */ }","preventionTips":["Pair every Attach with exactly one Detach","Own the visual lifecycle in one place","Never share host visuals between renderers","Guard re-entrant initialization paths"],"tags":["ink","renderer","visual","state"],"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"}