dotnet/wpf · error · ArgumentNullException

SR.EventArgIsNull

Error message

SR.EventArgIsNull

What it means

StrokeCollection.OnStrokesChanged — the protected virtual event-raiser invoked via RaiseStrokesChanged — throws ArgumentNullException with SR.EventArgIsNull when the StrokeCollectionChangedEventArgs e is null. Derived classes overriding or invoking this method must always supply a real event-args object describing the added/removed strokes.

Solutions

  1. Always construct StrokeCollectionChangedEventArgs with non-null added/removed StrokeCollection instances before calling OnStrokesChanged.
  2. Guard the call site: if (args != null) OnStrokesChanged(args).
  3. In a subclass override, do not call base.OnStrokesChanged with a null value; rebuild a default args object if data is missing.

Example fix

// before
OnStrokesChanged(args); // args may be null
// after
args ??= new StrokeCollectionChangedEventArgs(new StrokeCollection(), new StrokeCollection());
OnStrokesChanged(args);
Defensive patterns

Strategy: validation

Validate before calling

if (e != null)
    OnStrokesChanged(e);

Type guard

static bool CanRaise(StrokeCollectionChangedEventArgs e) => e != null;

Try / catch

try { OnStrokesChanged(e); }
catch (ArgumentNullException ex) when (ex.ParamName == "e") { /* supply a real args object */ }

Prevention

When it happens

Trigger: Calling OnStrokesChanged(null) from derived-class code or RaiseStrokesChanged with an uninitialized args object; constructing change args lazily and passing null when no change data was captured.

Common situations: Custom StrokeCollection subclasses that raise change notifications manually; reflection/testing code invoking the protected method with default args; refactoring that left a null args path in place.

Related errors


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

Appendix: source

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

            add { _collectionChanged += value; }
            remove { _collectionChanged -= value; }
        }


        /// <summary>Method called on derived classes whenever a drawing attributes
        /// change has occurred in the stroke references in the collection</summary>
        /// <param name="e">The change information for the stroke collection</param>
        /// <remarks>StrokesChanged will not be called when drawing attributes or
        /// custom attributes are changed. Changes that trigger StrokesChanged
        /// include packets or points changing, modified tranforms, and stroke objects
        /// being added or removed from the collection.
        /// To ensure that events fire for event listeners, derived classes
        /// should call this method.</remarks>
        protected virtual void OnStrokesChanged(StrokeCollectionChangedEventArgs e)
        {
            if ( null == e )
            {
                throw new ArgumentNullException(nameof(e), SR.EventArgIsNull);
            }

            //raise our internal event first.  This is used by
            //our Renderer and IncrementalHitTester since if they can assume
            //they are the first in the delegate chain, they can be optimized
            //to not have to handle out of order events caused by 3rd party code
            //getting called first
            if ( this.StrokesChangedInternal != null)
            {
                this.StrokesChangedInternal(this, e);
            }
            if ( this.StrokesChanged != null )
            {
                this.StrokesChanged(this, e);
            }
            if ( _collectionChanged != null )
            {
                //raise CollectionChanged.  We support the following 

View on GitHub (pinned to 81131a70a4)