dotnet/wpf · error · ArgumentException
SR.AccessKeyManager_NotAUnicodeCharacter
Error message
SR.AccessKeyManager_NotAUnicodeCharacter
What it means
AccessKeyManager.NormalizeKey throws ArgumentException when the given access key string is not a single Unicode character (a text element). WPF access keys are exactly one character, so multi-character strings are rejected before normalization via ToUpperInvariant. The SR resource AccessKeyManager_NotAUnicodeCharacter supplies the message naming the offending 'key' argument.
Solutions
- Pass exactly one character: key.Substring(0,1) or a char.ToString() value.
- Validate the string with StringInfo.GetNextTextElement(key) == key before calling the API.
- Strip modifier prefixes (e.g. "_") and take only the access character, which is what UIHelper/Label does for _Mnemonics.
Example fix
// before
AccessKeyManager.Register("Ctrl+K", window);
// after
AccessKeyManager.Register("K", window); Defensive patterns
Strategy: validation
Validate before calling
static bool IsSingleUnicodeChar(string key) =>
!string.IsNullOrEmpty(key) && StringInfo.GetNextTextElement(key) == key; Type guard
static string ToAccessKey(object value)
{
var s = value as string;
return (s != null && s.Length == 1) ? s.ToUpperInvariant() : null;
} Try / catch
try { AccessKeyManager.Register(key, target); }
catch (ArgumentException ex) when (ex.Message.Contains("AccessKeyManager"))
{ /* log: key must be a single Unicode character */ } Prevention
- Always derive the access key from a single char (e.g. label text preceded by '_').
- Never pass multi-character strings like "Ctrl+K" or "F1" to AccessKeyManager APIs.
- Unit-test access key extraction with surrogate-pair characters.
When it happens
Trigger: Calling AccessKeyManager.Register, Unregister, IsKeyRegistered, or ProcessKey with a key string whose full text differs from its first text element — i.e. any string longer than one grapheme, such as "AB", surrogate-pair misuse, or an empty string (empty yields firstCharacter="" and ""!="" is false only when key==""... actually GetNextTextElement("") returns "" so empty passes null check but throws here only when key.Length>1).
Common situations: Binding an access key to a label substring or a localized string without slicing out a single character; passing a user-typed string or a config value like "F1" or "Esc" instead of a single character; concatenating modifiers with the key ("Ctrl+K").
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- " }} " element found. Expected fixed page element ( }} ).
- ' ' ContentType is not valid.
- ' ' ID is not a valid XSD ID.
- array
- Cannot pass multidimensional array to the CopyTo method on…
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/9c9ab322fc0c8fdb.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Input/AccessKeyManager.cs:125
AccessKeyManager akm = AccessKeyManager.Current;
return (akm.ProcessKeyForScope(scope, key, isMultiple,false) == ProcessKeyResult.MoreMatches);
}
/// <summary>
/// Returns StringInfo.GetNextTextElement(key).ToUpperInvariant() throwing exceptions for null
/// and multi-char strings.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static string NormalizeKey(string key)
{
ArgumentNullException.ThrowIfNull(key);
string firstCharacter = StringInfo.GetNextTextElement(key);
if (key != firstCharacter)
{
throw new ArgumentException(SR.Format(SR.AccessKeyManager_NotAUnicodeCharacter, "key"));
}
return firstCharacter.ToUpperInvariant();
}
/// <summary>
/// This event is used by elements that want to define a scope for accesskeys, such as Menu and Popup.
/// This event will never be raised, it is used to identify classes that define new scopes.
/// </summary>
public static readonly RoutedEvent AccessKeyPressedEvent = EventManager.RegisterRoutedEvent(
"AccessKeyPressed", RoutingStrategy.Bubble, typeof(AccessKeyPressedEventHandler), typeof(AccessKeyManager));
/// <summary>
/// Adds a handler for the AccessKeyPressed attached event
/// </summary>
/// <param name="element">UIElement or ContentElement that listens to this event</param>
/// <param name="handler">Event Handler to be added</param>
public static void AddAccessKeyPressedHandler(DependencyObject element, AccessKeyPressedEventHandler handler)View on GitHub (pinned to 81131a70a4)