dotnet/wpf · error · ArgumentException
SR.KeyboardSinkAlreadyOwned
Error message
SR.KeyboardSinkAlreadyOwned
What it means
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.
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.
Example fix
// before sourceA.RegisterKeyboardInputSink(sink); sourceB.RegisterKeyboardInputSink(sink); // throws: already owned // after sourceA.RegisterKeyboardInputSink(sink); var sinkB = CreateNewSink(); // one sink per source sourceB.RegisterKeyboardInputSink(sinkB);
Defensive patterns
Strategy: validation
Validate before calling
if (sink.KeyboardInputSite != null)
throw new InvalidOperationException("Sink already registered"); // or skip
source.RegisterKeyboardInputSink(sink); Try / catch
try
{
source.RegisterKeyboardInputSink(sink);
}
catch (ArgumentException)
{
// sink already owned by another site; create or reuse appropriately
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- SR.KeyboardSinkNotAChild
- SR.OnlyAcceptsKeyMessages
- SR.OnlyAcceptsKeyMessages
- Win32Exception(Marshal.GetLastWin32Error())
- Win32Exception
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c2ce678129d0b6e9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSource.cs:1913
/// </summary>
/// <remarks>
/// This API requires unrestricted UI Window permission.
/// We explicitly don't make this method overridable as we want to keep the
/// precise implementation fixed and make sure the _keyboardInputSinkChildren
/// state is kep consistent. By making the method protected, implementors can
/// still call into it when required. Notice as calls are made through the
/// IKIS interface, there's still a way for advanced developers to override
/// the behavior by re-implementing the interface.
/// </remarks>
protected IKeyboardInputSite RegisterKeyboardInputSinkCore(IKeyboardInputSink sink)
{
CheckDisposed(true);
ArgumentNullException.ThrowIfNull(sink);
if (sink.KeyboardInputSite != null)
{
throw new ArgumentException(SR.KeyboardSinkAlreadyOwned);
}
HwndSourceKeyboardInputSite site = new HwndSourceKeyboardInputSite(this, sink);
if (_keyboardInputSinkChildren == null)
_keyboardInputSinkChildren = new List<HwndSourceKeyboardInputSite>();
_keyboardInputSinkChildren.Add(site);
return site;
}
IKeyboardInputSite IKeyboardInputSink.RegisterKeyboardInputSink(IKeyboardInputSink sink)
{
return RegisterKeyboardInputSinkCore(sink);
}
/// <summary>
/// Gives the component a chance to process keyboard input.View on GitHub (pinned to 81131a70a4)