{"record":{"id":"c2ce678129d0b6e9","repo":"dotnet/wpf","slug":"sr-keyboardsinkalreadyowned","errorCode":null,"errorMessage":"SR.KeyboardSinkAlreadyOwned","messagePattern":"SR\\.KeyboardSinkAlreadyOwned","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs","lineNumber":1913,"sourceCode":"        /// </summary>\n        /// <remarks>\n        ///     This API requires unrestricted UI Window permission.\n        ///     We explicitly don't make this method overridable as we want to keep the\n        ///     precise implementation fixed and make sure the _keyboardInputSinkChildren\n        ///     state is kep consistent. By making the method protected, implementors can\n        ///     still call into it when required. Notice as calls are made through the\n        ///     IKIS interface, there's still a way for advanced developers to override\n        ///     the behavior by re-implementing the interface.\n        /// </remarks>\n        protected IKeyboardInputSite RegisterKeyboardInputSinkCore(IKeyboardInputSink sink)\n        {\n            CheckDisposed(true);\n\n            ArgumentNullException.ThrowIfNull(sink);\n\n            if (sink.KeyboardInputSite != null)\n            {\n                throw new ArgumentException(SR.KeyboardSinkAlreadyOwned);\n            }\n\n            HwndSourceKeyboardInputSite site = new HwndSourceKeyboardInputSite(this, sink);\n\n            if (_keyboardInputSinkChildren == null)\n                _keyboardInputSinkChildren = new List<HwndSourceKeyboardInputSite>();\n            _keyboardInputSinkChildren.Add(site);\n\n            return site;\n        }\n\n        IKeyboardInputSite IKeyboardInputSink.RegisterKeyboardInputSink(IKeyboardInputSink sink)\n        {\n            return RegisterKeyboardInputSinkCore(sink);\n        }\n\n        /// <summary>\n        ///     Gives the component a chance to process keyboard input.","sourceCodeStart":1895,"sourceCodeEnd":1931,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs#L1895-L1931","documentation":"HwndSource.RegisterKeyboardInputSink attaches an IKeyboardInputSink as a child keyboard sink. A sink can only be owned by one site, so if sink.KeyboardInputSite is already non-null the method throws ArgumentException(SR.KeyboardSinkAlreadyOwned). This keeps the keyboard-focus/sink ownership graph acyclic and one-to-one.","triggerScenarios":"Calling RegisterKeyboardInputSink with a sink that was previously registered (with this or another HwndSource/Window) without first clearing its KeyboardInputSite; re-registering the same child control's sink after reparenting.","commonSituations":"Reparenting hosted WinForms/ActiveX-style interop controls between windows; reusing a cached IKeyboardInputSink instance across multiple HwndSources; re-adding a control that was already registered.","solutions":["Register each sink only once; keep a flag or set of registered sinks to avoid duplicate registration.","If reparenting, remove the sink from the previous owner first so its KeyboardInputSite is cleared before re-registering.","Use distinct sink instances per HwndSource rather than sharing one sink object."],"exampleFix":"// before\nsourceA.RegisterKeyboardInputSink(sink);\nsourceB.RegisterKeyboardInputSink(sink); // throws: already owned\n// after\nsourceA.RegisterKeyboardInputSink(sink);\nvar sinkB = CreateNewSink(); // one sink per source\nsourceB.RegisterKeyboardInputSink(sinkB);\n","handlingStrategy":"validation","validationCode":"if (sink.KeyboardInputSite != null)\n    throw new InvalidOperationException(\"Sink already registered\"); // or skip\nsource.RegisterKeyboardInputSink(sink);","typeGuard":null,"tryCatchPattern":"try\n{\n    source.RegisterKeyboardInputSink(sink);\n}\ncatch (ArgumentException)\n{\n    // sink already owned by another site; create or reuse appropriately\n}","preventionTips":["Track registered sinks in a HashSet to prevent duplicate registration.","Use one sink instance per HwndSource.","Clear a sink's site (unregister from old owner) before reparenting."],"tags":["argument","keyboard","interop","ownership"],"backgroundTag":"invalid-argument-value","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"}