{"record":{"id":"505175b2f1ff986f","repo":"dotnet/wpf","slug":"sr-cannotbothbenull-formatted-with-added-removed","errorCode":null,"errorMessage":"SR.CannotBothBeNull (formatted with 'added', 'removed')","messagePattern":"SR\\.CannotBothBeNull \\(formatted with 'added', 'removed'\\)","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/Events.cs","lineNumber":37,"sourceCode":"    public class StrokeCollectionChangedEventArgs : EventArgs\n    {\n        private StrokeCollection.ReadOnlyStrokeCollection _added;\n        private StrokeCollection.ReadOnlyStrokeCollection _removed;\n        private int _index = -1;\n\n        /// <summary>Constructor</summary>\n        internal StrokeCollectionChangedEventArgs(StrokeCollection added, StrokeCollection removed, int index) :\n            this(added, removed)\n        {\n            _index = index;\n        }\n\n        /// <summary>Constructor</summary>\n        public StrokeCollectionChangedEventArgs(StrokeCollection added, StrokeCollection removed)\n        {\n            if ( added == null && removed == null )\n            {\n                throw new ArgumentException(SR.Format(SR.CannotBothBeNull, \"added\", \"removed\"));\n            }\n            _added = ( added == null ) ? null : new StrokeCollection.ReadOnlyStrokeCollection(added);\n            _removed = ( removed == null ) ? null : new StrokeCollection.ReadOnlyStrokeCollection(removed);\n        }\n\n        /// <summary>Set of strokes that where added, result may be an empty collection</summary>\n        public StrokeCollection Added\n        {\n            get\n            {\n                if ( _added == null )\n                {\n                    _added = new StrokeCollection.ReadOnlyStrokeCollection(new StrokeCollection());\n                }\n                return _added;\n            }\n        }\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/Events.cs#L19-L55","documentation":"The StrokeCollectionChangedEventArgs constructor requires at least one of the added/removed collections to be non-null; both being null leaves the event without any meaningful payload. This ArgumentException is thrown when constructing the event args with two nulls.","triggerScenarios":"Subclassing or raising a StrokeCollectionChanged event manually with new StrokeCollectionChangedEventArgs(null, null).","commonSituations":"Custom ink hosts forwarding stroke changes; test harnesses constructing event args with uninitialized collections.","solutions":["Pass at least one non-null StrokeCollection (use an empty StrokeCollection to indicate no changes)","Guard before constructing: if both sources are null, skip raising the event"],"exampleFix":"// before\nnew StrokeCollectionChangedEventArgs(null, null);\n// after\nnew StrokeCollectionChangedEventArgs(added ?? new StrokeCollection(), removed ?? new StrokeCollection());","handlingStrategy":"validation","validationCode":"if (added == null && removed == null) return; // skip raising event","typeGuard":"static bool IsValidStrokeChangeArgs(StrokeCollection a, StrokeCollection r) => a != null || r != null;","tryCatchPattern":"try { var e = new StrokeCollectionChangedEventArgs(added, removed); OnChanged(e); } catch (ArgumentException) { /* both null: no change to report */ }","preventionTips":["Pass empty StrokeCollection instances instead of null for 'no change' sides","Never construct event args manually with all-null parameters","Validate event payload before raising"],"tags":["wpf","ink","argumentexception","event-args"],"backgroundTag":"null-argument","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}