dotnet/wpf · error · InvalidOperationException
Cannot attach a Visual that is already attached.
Error message
Cannot attach a Visual that is already attached.
What it means
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.
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
Example fix
// before
renderer.AttachIncrementalRendering(hostVisual, constraints); // may run twice
// after
if (!attached.Contains(hostVisual))
{
renderer.AttachIncrementalRendering(hostVisual, constraints);
attached.Add(hostVisual);
} Defensive patterns
Strategy: validation
Validate before calling
// Track attached visuals yourself bool alreadyAttached = attachedVisuals.Contains(hostVisual); if (!alreadyAttached) renderer.AttachIncrementalRendering(hostVisual, strokers);
Type guard
bool CanAttach(Renderer r, Visual v) => v != null && !attachedVisuals.Contains(v);
Try / catch
try { renderer.AttachIncrementalRendering(visual, strokers); }
catch (InvalidOperationException) { /* already attached - skip */ } Prevention
- 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
When it happens
Trigger: Calling AttachIncrementalRendering twice with the same visual, or attaching a visual already attached through another InkPresenter/Renderer sharing it.
Common situations: Re-initializing an InkCanvas/dynamic renderer without detaching first, attaching the same host visual to multiple renderers, event handler re-entrancy causing double attach.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Specified Visual cannot be detached.
- Unrecognized Stroke in…
- ArgumentOutOfRangeException(nameof(oldProperty))
- ArgumentOutOfRangeException(nameof(percentageWithinBounds))
- ArgumentOutOfRangeException(nameof(percentageWithinLasso))
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/dc3cccd32826a556.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/MS/internal/Ink/Renderer.cs:289
/// <param name="drawingAttributes">drawing attributes that used in the incremental rendering</param>
internal void AttachIncrementalRendering(Visual visual, DrawingAttributes drawingAttributes)
{
// Check the input parameters
ArgumentNullException.ThrowIfNull(visual);
ArgumentNullException.ThrowIfNull(drawingAttributes);
//harden against eaten exceptions
bool exceptionRaised = false;
// Verify that the visual hasn't been attached already
if (_attachedVisuals != null)
{
foreach(Visual alreadyAttachedVisual in _attachedVisuals)
{
if (visual == alreadyAttachedVisual)
{
exceptionRaised = true;
throw new System.InvalidOperationException(SR.CannotAttachVisualTwice);
}
}
}
else
{
// Create the list to register attached visuals in
_attachedVisuals = new List<Visual>();
}
if (!exceptionRaised)
{
// The position of the visual in the tree depends on the drawingAttributes
// Find the appropriate parent visual to attach this visual to.
ContainerVisual parent = drawingAttributes.IsHighlighter ? GetContainerVisual(drawingAttributes) : _incrementalRenderingVisuals;
// Attach the visual to the tree
parent.Children.Add(visual);View on GitHub (pinned to 81131a70a4)