{"record":{"id":"ad984d9d237f756f","repo":"AvaloniaUI/Avalonia","slug":"immediatedrawingcontext","errorCode":null,"errorMessage":"ImmediateDrawingContext","messagePattern":"ImmediateDrawingContext","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Media/ImmediateDrawingContext.cs","lineNumber":227,"sourceCode":"            private readonly ImmediateDrawingContext _context;\n            private readonly Matrix _matrix;\n            private readonly PushedStateType _type;\n\n            public enum PushedStateType\n            {\n                None,\n                Matrix,\n                Opacity,\n                Clip,\n                MatrixContainer,\n                GeometryClip,\n                OpacityMask,\n            }\n\n            internal PushedState(ImmediateDrawingContext context, PushedStateType type, Matrix matrix = default)\n            {\n                if (context._states is null)\n                    throw new ObjectDisposedException(nameof(ImmediateDrawingContext));\n\n                _context = context;\n                _type = type;\n                _matrix = matrix;\n                _level = context._currentLevel += 1;\n                context._states.Push(this);\n            }\n\n            public void Dispose()\n            {\n                if (_type == PushedStateType.None)\n                    return;\n                if (_context._states is null || _context._transformContainers is null)\n                    throw new ObjectDisposedException(nameof(DrawingContext));\n                if (_context._currentLevel != _level)\n                    throw new InvalidOperationException(\"Wrong Push/Pop state order\");\n                _context._currentLevel--;\n                _context._states.Pop();","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Media/ImmediateDrawingContext.cs#L209-L245","documentation":"The PushedState constructor throws ObjectDisposedException(nameof(ImmediateDrawingContext)) when context._states is null. _states is returned to the pool and nulled in Dispose(), so any push (PushTransform, PushClip, PushOpacity, etc.) attempted after the context is disposed fails here.","triggerScenarios":"Calling any Push* method on an ImmediateDrawingContext whose Dispose() already ran — e.g. using a context from a completed render or storing a context field that was disposed and then drawing later.","commonSituations":"Reusing a DrawingContext after the using-block exited; drawing from a background thread after the UI context was disposed; deferred draw operations that outlive the context.","solutions":["Do not use an ImmediateDrawingContext after Dispose(); scope all draws inside its using lifetime.","Track disposal and short-circuit deferred draw operations.","Obtain a fresh context per render pass instead of reusing one."],"exampleFix":"// before\nusing (var ctx = ...CreateDrawingContext()) { /* ... */ }\nctx.PushTransform(m); // ctx already disposed -> throws\n\n// after - keep all drawing inside the using scope\nusing (var ctx = ...CreateDrawingContext())\n{\n    ctx.PushTransform(m);\n}","handlingStrategy":"validation","validationCode":"// Ensure no Push* call happens after the context is disposed.\nif (ctx is null) return;\n// Inside the using-scope only:\nusing (ctx.PushTransform(m)) { /* draw */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep all Push*/draw calls inside the context's using-scope.","Do not store a context for reuse across render passes.","Cancel deferred draw operations when the context is disposed."],"tags":["rendering","drawingcontext","objectdisposed","lifecycle"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}