{"record":{"id":"28bb8a5a9b6e0305","repo":"dotnet/wpf","slug":"sr-touch-devicealreadyactivated","errorCode":null,"errorMessage":"SR.Touch_DeviceAlreadyActivated","messagePattern":"SR\\.Touch_DeviceAlreadyActivated","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TouchDevice.cs","lineNumber":694,"sourceCode":"                _reevaluateOver = null;\n\n                OnHitTestInvalidatedAsync(this, EventArgs.Empty);\n            }\n\n            bool handled = RaiseTouchUp();\n            _isDown = false;\n            UpdateDirectlyOver(isSynchronize: false);\n            OnUpdated();\n\n            Touch.ReportFrame();\n            return handled;\n        }\n\n        protected void Activate()\n        {\n            if (_isActive)\n            {\n                throw new InvalidOperationException(SR.Touch_DeviceAlreadyActivated);\n            }\n\n            PromotingToManipulation = false;\n            AddActiveDevice(this);\n            AttachTouchDevice();\n            Synchronize();\n\n            if (_activeDevices.Count == 1)\n            {\n                _isPrimary = true;\n            }\n\n            _isActive = true;\n\n            if (Activated != null)\n            {\n                Activated(this, EventArgs.Empty);\n            }","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/TouchDevice.cs#L676-L712","documentation":"TouchDevice.Activate registers the touch device with the input system (AddActiveDevice, AttachTouchDevice, Synchronize). A device may only be activated once; if _isActive is already true, Activate throws InvalidOperationException(Touch_DeviceAlreadyActivated). This is a state-machine guard: double activation would corrupt the active-device list and event routing.","triggerScenarios":"Calling Activate() (from a TouchDevice subclass, e.g. a custom stylus/touch provider) a second time without an intervening Deactivate(); calling Activate from both a touchdown handler and an initialization path; re-activating after a reset that did not actually clear _isActive.","commonSituations":"Custom touch/stylus integration code (e.g. simulated touch drivers, Windows Ink interop) that activates the device in multiple lifecycle callbacks; re-entrancy when the same device is reported by several input reports; test harnesses activating fixtures repeatedly.","solutions":["Track activation state in your device wrapper and call Activate() only when it has never been activated or after a successful Deactivate().","Structure the provider so Activate is invoked exactly once from a single lifecycle hook (e.g. OnTabletAdded), not from every input report.","Wrap the call so re-activation is a no-op instead of an exception path."],"exampleFix":"// before\nprotected override void OnCreated()\n{\n    Activate();\n}\nprotected override void OnEnabled() // may fire after OnCreated\n{\n    Activate(); // InvalidOperationException: already activated\n}\n\n// after\nprivate bool _activated;\nprivate void EnsureActivated()\n{\n    if (!_activated)\n    {\n        Activate();\n        _activated = true;\n    }\n}","handlingStrategy":"validation","validationCode":"if (device.IsActive) return; // skip Activate when already active","typeGuard":null,"tryCatchPattern":"try { device.Activate(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"activated\"))\n{\n    // already active — treat as success\n}","preventionTips":["Call Activate exactly once from a single lifecycle hook.","Mirror every Activate with a Deactivate and track it with your own flag.","Never activate from per-input-report callbacks."],"tags":["wpf","touch","invalid-operation","state-machine"],"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"}