dotnet/wpf · error · NotSupportedException

SR.StrokeCollectionIsReadOnly

Error message

SR.StrokeCollectionIsReadOnly

What it means

ReadOnlyStrokeCollection overrides OnStrokesChanged to throw NotSupportedException, because the collection is immutable. Any API that would add, remove, clip, or erase strokes on a read-only collection is rejected. Read-only collections are typically used for presentation of ink that cannot be modified.

Solutions

  1. Check strokes.IsReadOnly before mutating and take a writable copy first: new StrokeCollection(strokes)
  2. Use the original, writable InkCanvas.Strokes collection instead of the read-only snapshot
  3. Avoid calling mutating APIs like Clip/Erase on read-only collections; perform hit-testing only

Example fix

// before
readOnlyStrokes.Add(newStroke); // NotSupportedException
// after
var writable = new StrokeCollection(readOnlyStrokes);
writable.Add(newStroke);
Defensive patterns

Strategy: validation

Validate before calling

if (strokes.IsReadOnly) strokes = new StrokeCollection(strokes);

Type guard

bool IsWritable(StrokeCollection sc) => sc != null && !sc.IsReadOnly;

Prevention

When it happens

Trigger: Calling StrokeCollection mutating members (Add, Remove, Insert, Clip, Erase, Clear, indexer set) on a StrokeCollection obtained from a read-only source such as ReadOnlyStrokeCollection returned by certain InkCanvas/Ink APIs; the mutation raises OnStrokesChanged which throws.

Common situations: Attempting ink.Erase(...) or strokes.Add(...) on a collection fetched from an InkCanvas in read-only mode, or after wrapping strokes in AsReadOnly; often a surprise because the method exists but the collection is immutable.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        /// </summary>
        internal class ReadOnlyStrokeCollection : StrokeCollection, ICollection<Stroke>, IList
        {
            internal ReadOnlyStrokeCollection(StrokeCollection strokeCollection)
            {
                if ( strokeCollection != null )
                {
                    ( (List<Stroke>)this.Items ).AddRange(strokeCollection);
                }
            }

            /// <summary>
            /// Change is not allowed.  We would override SetItem, InsertItem etc but 
            /// they need to be sealed on StrokeCollection to prevent dupes from being added
            /// </summary>
            /// <param name="e"></param>
            protected override void OnStrokesChanged(StrokeCollectionChangedEventArgs e)
            {
                throw new NotSupportedException(SR.StrokeCollectionIsReadOnly);
            }

            /// <summary>
            /// IsReadOnly
            /// </summary>
            bool IList.IsReadOnly
            {
                get { return true; }
            }

            /// <summary>
            /// IsReadOnly
            /// </summary>
            bool ICollection<Stroke>.IsReadOnly
            {
                get { return true; }
            }
        }

View on GitHub (pinned to 81131a70a4)