dotnet/wpf · error · ArgumentNullException

SR.SCEraseShape

Error message

SR.SCEraseShape

What it means

StrokeCollection.Erase(IEnumerable<Point> eraserPath, StylusShape eraserShape) requires a non-null eraser shape; a null shape throws ArgumentNullException whose message is SR.SCEraseShape. The shape defines the tip geometry (e.g. rectangle/ellipse) of the erasing stroke.

Solutions

  1. Construct a shape before calling: new EllipseStylusShape(w, h) or RectangleStylusShape
  2. Guard: if (eraserShape == null) use a default shape
  3. Initialize the tool state so the shape always exists when erasing is enabled

Example fix

// before
strokes.Erase(path, currentShape); // currentShape may be null
// after
var shape = currentShape ?? new EllipseStylusShape(10, 10);
strokes.Erase(path, shape);
Defensive patterns

Strategy: type-guard

Validate before calling

if (eraserShape == null) eraserShape = new EllipseStylusShape(10, 10);

Type guard

bool HasShape(StylusShape s) => s != null;

Try / catch

try { strokes.Erase(path, shape); } catch (ArgumentNullException) { strokes.Erase(path, new EllipseStylusShape(10, 10)); }

Prevention

When it happens

Trigger: Calling the shaped Erase overload with eraserShape == null, e.g. a StylusShape field never initialized, or a settings lookup that returned null when the eraser type is unknown.

Common situations: Custom eraser tools where the shape is created lazily on first stylus input but the erase call happens first; deserialized tool configuration missing the shape; refactors replacing a default shape with a nullable one.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/ed9e4ca76c49d97b. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/StrokeCollection2.cs:318

        {
            if (!bounds.IsEmpty)
            {
                Erase(new Point[4] { bounds.TopLeft, bounds.TopRight, bounds.BottomRight, bounds.BottomLeft });
            }
        }


        /// <summary>
        /// Erases all ink hit by the contour of an erasing stroke
        /// </summary>
        /// <param name="eraserShape">Shape of the eraser</param>
        /// <param name="eraserPath">a path making the spine of the erasing stroke </param>
        public void Erase(IEnumerable<Point> eraserPath, StylusShape eraserShape)
        {
            // Check the input parameters
            if (eraserShape == null)
            {
                throw new System.ArgumentNullException(SR.SCEraseShape);
            }
            if (eraserPath == null)
            {
                throw new System.ArgumentNullException(SR.SCErasePath);
            }
            if (IEnumerablePointHelper.GetCount(eraserPath) == 0)
            {
                return;
            }

            ErasingStroke erasingStroke = new ErasingStroke(eraserShape, eraserPath);
            for (int i = 0; i < this.Count; i++)
            {
                Stroke stroke = this[i];

                List<StrokeIntersection> intersections = new List<StrokeIntersection>();
                erasingStroke.EraseTest(StrokeNodeIterator.GetIterator(stroke, stroke.DrawingAttributes), intersections);
                StrokeCollection eraseResult = stroke.Erase(intersections.ToArray());

View on GitHub (pinned to 81131a70a4)