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

  1. Register each sink only once; keep a flag or set of registered sinks to avoid duplicate registration.
  2. If reparenting, remove the sink from the previous owner first so its KeyboardInputSite is cleared before re-registering.
  3. 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

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


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)