dotnet/wpf · error · InvalidOperationException
SR.AttachedPropertyOnDictionaryKey
Error message
SR.AttachedPropertyOnDictionaryKey
What it means
Same invariant as the property case, but for dictionary keys: XamlObjectReader serializes dictionary keys as strings/type-converted values, and if a key object has attached properties set (GetAttachedProperties returns non-null) those would be lost in the x:Key representation. The reader throws an InvalidOperationException naming the key value and the attached property.
Solutions
- Use simple immutable values (string, int, enum) as dictionary keys instead of objects carrying attached properties.
- Clear the attached-property values from the key object before serialization (call ClearValue for each attached property).
- Restructure the data so the rich object becomes a value inside the entry rather than the key.
Example fix
// before key = new FrameworkElement(); Canvas.SetTop(key, 5); dictionary[key] = value; // key serialized via x:Key → throws // after key = "myKey"; // use a simple key without attached properties dictionary[key] = value;
Defensive patterns
Strategy: validation
Validate before calling
if (key is DependencyObject d) {
if (d.ReadLocalValue(Canvas.LeftProperty) != DependencyProperty.UnsetValue)
throw new InvalidOperationException("Key has attached properties; use a simple key.");
} Type guard
bool IsSimpleKey(object k) => k is string || k is int || k is long || k is Enum || k is Type;
Try / catch
try { SerializeDictionary(dict); }
catch (InvalidOperationException ex) when (ex.Message.Contains("attached")) { /* rebuild dict with simple keys */ } Prevention
- Use strings/enums/ints as XAML-serialized dictionary keys.
- Never use DependencyObjects as dictionary keys.
- ClearValue attached properties before serialization if rich keys are unavoidable.
When it happens
Trigger: Reading an IDictionary where the key object (serialized via x:Key, property == null in ThrowIfPropertiesAreAttached) exposes attached properties — XamlObjectReader.cs:910-912.
Common situations: Using UI elements or rich objects as dictionary keys while attached properties (Grid.Row, Canvas.Left, AutomationProperties) were set on them; keyed ResourceDictionary-like structures serialized with XamlObjectReader.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- ArgumentException: path
- ArgumentException: relativeTo
- ArgumentNullException: path
- ArgumentNullException: relativeTo
- InitializationState !=
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/7b96897f75f68788.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlObjectReader.cs:912
valueInfo = ObjectMarkupInfo.ForObject(propertyValue, context, propertyConverter);
}
}
return valueInfo;
}
private static void ThrowIfPropertiesAreAttached(object value, XamlMember property, SerializerContext context)
{
var props = context.Runtime.GetAttachedProperties(value);
if (props is not null)
{
if (property is not null)
{
throw new InvalidOperationException(SR.Format(SR.AttachedPropertyOnTypeConvertedOrStringProperty, property.Name, value.ToString(), props[0].Key.ToString()));
}
else
{
throw new InvalidOperationException(SR.Format(SR.AttachedPropertyOnDictionaryKey, value.ToString(), props[0].Key.ToString()));
}
}
}
// Reproduce the logic of System.ComponentModel.ReflectPropertyDescriptor.ShouldSerializeValue
private static bool ShouldWriteProperty(object source, XamlMember property, SerializerContext context)
{
bool isReadOnly = !context.IsPropertyWriteVisible(property);
if (!isReadOnly)
{
object defaultValue;
if (GetDefaultValue(property, out defaultValue))
{
object actualValue = context.Runtime.GetValue(source, property);
return !Equals(defaultValue, actualValue);
}
}View on GitHub (pinned to 81131a70a4)