{"record":{"id":"7b96897f75f68788","repo":"dotnet/wpf","slug":"sr-attachedpropertyondictionarykey","errorCode":null,"errorMessage":"SR.AttachedPropertyOnDictionaryKey","messagePattern":"SR\\.AttachedPropertyOnDictionaryKey","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlObjectReader.cs","lineNumber":912,"sourceCode":"                        valueInfo = ObjectMarkupInfo.ForObject(propertyValue, context, propertyConverter);\n                    }\n                }\n\n                return valueInfo;\n            }\n\n            private static void ThrowIfPropertiesAreAttached(object value, XamlMember property, SerializerContext context)\n            {\n                var props = context.Runtime.GetAttachedProperties(value);\n                if (props is not null)\n                {\n                    if (property is not null)\n                    {\n                        throw new InvalidOperationException(SR.Format(SR.AttachedPropertyOnTypeConvertedOrStringProperty, property.Name, value.ToString(), props[0].Key.ToString()));\n                    }\n                    else\n                    {\n                        throw new InvalidOperationException(SR.Format(SR.AttachedPropertyOnDictionaryKey, value.ToString(), props[0].Key.ToString()));\n                    }\n                }\n            }\n\n            // Reproduce the logic of System.ComponentModel.ReflectPropertyDescriptor.ShouldSerializeValue\n            private static bool ShouldWriteProperty(object source, XamlMember property, SerializerContext context)\n            {\n                bool isReadOnly = !context.IsPropertyWriteVisible(property);\n\n                if (!isReadOnly)\n                {\n                    object defaultValue;\n                    if (GetDefaultValue(property, out defaultValue))\n                    {\n                        object actualValue = context.Runtime.GetValue(source, property);\n                        return !Equals(defaultValue, actualValue);\n                    }\n                }","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlObjectReader.cs#L894-L930","documentation":"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.","triggerScenarios":"Reading an IDictionary where the key object (serialized via x:Key, property == null in ThrowIfPropertiesAreAttached) exposes attached properties — XamlObjectReader.cs:910-912.","commonSituations":"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.","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."],"exampleFix":"// before\nkey = new FrameworkElement();\nCanvas.SetTop(key, 5);\ndictionary[key] = value; // key serialized via x:Key → throws\n// after\nkey = \"myKey\"; // use a simple key without attached properties\ndictionary[key] = value;","handlingStrategy":"validation","validationCode":"if (key is DependencyObject d) {\n  if (d.ReadLocalValue(Canvas.LeftProperty) != DependencyProperty.UnsetValue)\n    throw new InvalidOperationException(\"Key has attached properties; use a simple key.\");\n}","typeGuard":"bool IsSimpleKey(object k) => k is string || k is int || k is long || k is Enum || k is Type;\n","tryCatchPattern":"try { SerializeDictionary(dict); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"attached\")) { /* rebuild dict with simple keys */ }","preventionTips":["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."],"tags":["xaml","attached-property","dictionary"],"backgroundTag":"unsupported-operation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}