dotnet/wpf · error · ArgumentException

SR.KeyboardSinkMustBeAnElement

Error message

SR.KeyboardSinkMustBeAnElement

What it means

HwndSourceKeyboardInputSite's constructor requires the IKeyboardInputSink it wraps to also be a UIElement, because keyboard input routing in WPF depends on the sink having an element-based visual/hit-testing surface. If the sink is any other IKeyboardInputSink implementation, the constructor throws ArgumentException with resource key SR.KeyboardSinkMustBeAnElement naming the 'sink' parameter.

Solutions

  1. Make the sink derive from UIElement (e.g. subclass HwndHost or another UIElement) and implement IKeyboardInputSink there
  2. If the sink cannot be a UIElement, register it as a child sink via an existing UIElement sink's ChildKeyboardInputSinks instead of constructing the site directly

Example fix

// before
IKeyboardInputSink sink = new MyCustomSink();
var site = new HwndSourceKeyboardInputSite(source, sink); // throws
// after
class MySink : HwndHost, IKeyboardInputSink { ... }
var site = new HwndSourceKeyboardInputSite(source, new MySink());
Defensive patterns

Strategy: validation

Validate before calling

if (sink is not UIElement) throw new ArgumentException("sink must be a UIElement", nameof(sink));
var site = new HwndSourceKeyboardInputSite(source, sink);

Type guard

bool IsValidSink(IKeyboardInputSink s) => s is UIElement;

Prevention

When it happens

Trigger: Calling new HwndSourceKeyboardInputSite(source, sink) where sink is a custom or third-party IKeyboardInputSink that does not derive from UIElement (source or sink being null throws a different error first).

Common situations: Developers implementing IKeyboardInputSink on a plain class or a Control-derived-non-UIElement type to host WinForms/Win32 interop content, then wiring it as the root sink for an HwndSource.

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/e1cddb50646e9f8d. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSourceKeyboardInputSite.cs:16

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Windows.Input;

namespace System.Windows.Interop
{
    internal class HwndSourceKeyboardInputSite : IKeyboardInputSite
    {
        public HwndSourceKeyboardInputSite(HwndSource source, IKeyboardInputSink sink)
        {
            ArgumentNullException.ThrowIfNull(source);
            ArgumentNullException.ThrowIfNull(sink);
            if (!(sink is UIElement))
            {
                throw new ArgumentException(SR.KeyboardSinkMustBeAnElement, nameof(sink));
            }
            
            _source = source;

            _sink = sink;
            _sink.KeyboardInputSite = this;

            _sinkElement = sink as UIElement;
        }
        
#region IKeyboardInputSite
        /// <summary>
        ///     Unregisters a child KeyboardInputSink from this sink.
        /// </summary>
        /// <remarks> 
        ///     Requires unmanaged code permission. 
        /// </remarks> 
        void IKeyboardInputSite.Unregister()

View on GitHub (pinned to 81131a70a4)