{"record":{"id":"3740b41c75f70d99","repo":"dotnet/wpf","slug":"sr-endhittestingcalled","errorCode":null,"errorMessage":"SR.EndHitTestingCalled","messagePattern":"SR\\.EndHitTestingCalled","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/IncrementalHitTester.cs","lineNumber":46,"sourceCode":"            AddPoints(new Point[1] { point });\n        }\n\n        /// <summary>\n        /// Adds an array of points representing an incremental move of the hit-testing tool\n        /// </summary>\n        /// <param name=\"points\">points representing an incremental move of the hitting tool</param>\n        public void AddPoints(IEnumerable<Point> points)\n        {\n            ArgumentNullException.ThrowIfNull(points);\n\n            if (IEnumerablePointHelper.GetCount(points) == 0)\n            {\n                throw new System.ArgumentException(SR.EmptyArrayNotAllowedAsArgument, nameof(points));\n            }\n\n            if (!_fValid)\n            {\n                throw new System.InvalidOperationException(SR.EndHitTestingCalled);\n            }\n\n            System.Diagnostics.Debug.Assert(_strokes != null);\n\n            AddPointsCore(points);\n        }\n\n        /// <summary>\n        /// Adds a StylusPacket representing an incremental move of the hit-testing tool\n        /// </summary>\n        /// <param name=\"stylusPoints\">stylusPoints</param>\n        public void AddPoints(StylusPointCollection stylusPoints)\n        {\n            ArgumentNullException.ThrowIfNull(stylusPoints);\n\n            if (stylusPoints.Count == 0)\n            {\n                throw new System.ArgumentException(SR.EmptyArrayNotAllowedAsArgument, nameof(stylusPoints));","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Ink/IncrementalHitTester.cs#L28-L64","documentation":"After EndHitTesting() is called the IncrementalHitTester is invalid; further AddPoints calls throw InvalidOperationException (SR.EndHitTestingCalled). This enforces the hit-tester's lifecycle: create → test → EndHitTesting.","triggerScenarios":"Calling AddPoints/AddPoint after EndHitTesting() on the same tester — e.g. reusing a tester stored in a field across stroke re-render or after cancellation.","commonSituations":"Long-lived hit-tester fields not reset when a new stroke erase begins; event handlers firing after hit-testing was concluded; async continuations running after EndHitTesting.","solutions":["Create a new IncrementalHitTester (via stroke.GetIncrementalHitTester/GetIncrementalStrokeHitTester) after EndHitTesting instead of reusing the old one","Track tester validity with a flag or check and skip AddPoints once invalidated","Wrap in try-catch InvalidOperationException to tolerate post-dispose events"],"exampleFix":"// before\nif (_hitTester != null) _hitTester.AddPoints(pts);\n// after\nif (_hitTester != null && _hitTesterValid) _hitTester.AddPoints(pts);","handlingStrategy":"try-catch","validationCode":"if (!_hitTesterValid) return;","typeGuard":"bool CanTest(IncrementalHitTester t, bool valid) => t != null && valid;","tryCatchPattern":"try { tester.AddPoints(pts); } catch (InvalidOperationException) { _hitTesterValid = false; }","preventionTips":["Set a validity flag when calling EndHitTesting and check it before every AddPoints","Dispose/replace stored testers at the start of each erase operation","Avoid async continuations that may run after EndHitTesting"],"tags":["wpf","ink","invalidoperationexception","object-disposed","hit-testing"],"backgroundTag":"invalid-state-transition","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"}