dotnet/wpf · error · ArgumentNullException

SR.EmptyScToReplaceWith

Error message

SR.EmptyScToReplaceWith

What it means

StrokeCollection.Replace(StrokeCollection, StrokeCollection) throws ArgumentException with SR.EmptyScToReplace when strokesToReplace is non-null but empty (Count == 0). An empty replacement set identifies no strokes, so the replace operation is undefined and rejected.

Solutions

  1. Guard with if (strokesToReplace.Count > 0) before calling Replace.
  2. Only invoke Replace when a prior operation (selection, hit test) actually produced strokes.
  3. Catch ArgumentException and treat it as a no-op in idempotent UI flows.

Example fix

// before
strokes.Replace(selectedStrokes, replacement); // selectedStrokes.Count == 0
// after
if (selectedStrokes.Count > 0)
    strokes.Replace(selectedStrokes, replacement);
Defensive patterns

Strategy: validation

Validate before calling

if (strokesToReplace != null && strokesToReplace.Count > 0)
    strokes.Replace(strokesToReplace, strokesToReplaceWith);

Type guard

static bool IsNonEmpty(StrokeCollection c) => c != null && c.Count > 0;

Try / catch

try { strokes.Replace(strokesToReplace, with); }
catch (ArgumentException ex) when (ex.ParamName == "strokesToReplace") { /* empty set: no-op */ }

Prevention

When it happens

Trigger: Calling Replace with a StrokeCollection constructed but never populated (new StrokeCollection()), or with a filtered subset that ended up empty (e.g. selected strokes after the selection was cleared).

Common situations: Replace-on-selection workflows where InkCanvas.GetSelectedStrokes() returned an empty collection; building the replace set inside a loop that never executed due to a predicate mismatch.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/StrokeCollection.cs:469

            StrokeCollection strokesToReplace = new StrokeCollection();
            strokesToReplace.Add(strokeToReplace);
            this.Replace(strokesToReplace, strokesToReplaceWith);
        }

        /// <summary>
        /// Replace
        /// </summary>
        /// <param name="strokesToReplace"></param>
        /// <param name="strokesToReplaceWith"></param>
        public void Replace(StrokeCollection strokesToReplace, StrokeCollection strokesToReplaceWith)
        {
            if ( strokesToReplace == null )
            {
                throw new ArgumentNullException(SR.EmptyScToReplace);
            }
            if ( strokesToReplaceWith == null )
            {
                throw new ArgumentNullException(SR.EmptyScToReplaceWith);
            }

            int replaceCount = strokesToReplace.Count;
            if ( replaceCount == 0 )
            {
                ArgumentException ae = new ArgumentException(SR.EmptyScToReplace, nameof(strokesToReplace));
                //
                // we add a tag here so we can check for this in EraserBehavior.OnPointEraseResultChanged
                // to determine if this method is the origin of an ArgumentException we harden against
                //
                ae.Data.Add("System.Windows.Ink.StrokeCollection", "");
                throw ae;
            }

            int[] indexes = this.GetStrokeIndexes(strokesToReplace);
            if ( indexes == null )
            {
                // At least one stroke doesn't exist in our collection. We throw.

View on GitHub (pinned to 81131a70a4)