{"record":{"id":"e1cddb50646e9f8d","repo":"dotnet/wpf","slug":"sr-keyboardsinkmustbeanelement","errorCode":null,"errorMessage":"SR.KeyboardSinkMustBeAnElement","messagePattern":"SR\\.KeyboardSinkMustBeAnElement","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSourceKeyboardInputSite.cs","lineNumber":16,"sourceCode":"﻿// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\nusing System.Windows.Input;\n\nnamespace System.Windows.Interop\n{\n    internal class HwndSourceKeyboardInputSite : IKeyboardInputSite\n    {\n        public HwndSourceKeyboardInputSite(HwndSource source, IKeyboardInputSink sink)\n        {\n            ArgumentNullException.ThrowIfNull(source);\n            ArgumentNullException.ThrowIfNull(sink);\n            if (!(sink is UIElement))\n            {\n                throw new ArgumentException(SR.KeyboardSinkMustBeAnElement, nameof(sink));\n            }\n            \n            _source = source;\n\n            _sink = sink;\n            _sink.KeyboardInputSite = this;\n\n            _sinkElement = sink as UIElement;\n        }\n        \n#region IKeyboardInputSite\n        /// <summary>\n        ///     Unregisters a child KeyboardInputSink from this sink.\n        /// </summary>\n        /// <remarks> \n        ///     Requires unmanaged code permission. \n        /// </remarks> \n        void IKeyboardInputSite.Unregister()","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/HwndSourceKeyboardInputSite.cs#L1-L34","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Make the sink derive from UIElement (e.g. subclass HwndHost or another UIElement) and implement IKeyboardInputSink there","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"],"exampleFix":"// before\nIKeyboardInputSink sink = new MyCustomSink();\nvar site = new HwndSourceKeyboardInputSite(source, sink); // throws\n// after\nclass MySink : HwndHost, IKeyboardInputSink { ... }\nvar site = new HwndSourceKeyboardInputSite(source, new MySink());","handlingStrategy":"validation","validationCode":"if (sink is not UIElement) throw new ArgumentException(\"sink must be a UIElement\", nameof(sink));\nvar site = new HwndSourceKeyboardInputSite(source, sink);","typeGuard":"bool IsValidSink(IKeyboardInputSink s) => s is UIElement;","tryCatchPattern":null,"preventionTips":["Implement IKeyboardInputSink on UIElement-derived classes (HwndHost) only","Never expose raw IKeyboardInputSink implementations to constructors expecting elements","Check the sink type at the interop boundary before wiring keyboard sites"],"tags":["wpf","interop","argument-exception","keyboard-input"],"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-22T01:17:13.364Z"}