{"record":{"id":"6c5835617dde9ee6","repo":"dotnet/wpf","slug":"sr-format-sr-propertytriggercycledetected-source-name","errorCode":null,"errorMessage":"SR.Format(SR.PropertyTriggerCycleDetected, source.Name)","messagePattern":"SR\\.Format\\(SR\\.PropertyTriggerCycleDetected, source\\.Name\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/TriggerBase.cs","lineNumber":247,"sourceCode":"\n            // Track Dependent/Source relationship for prediction\n            for (int i = 0; i < PropertyValues.Count; i++)\n            {\n                PropertyValue propertyValue = PropertyValues[i];\n\n                DependencyProperty dependent = propertyValue.Property;\n\n                for (int j = 0; j < propertyValue.Conditions.Length; j++)\n                {\n                    DependencyProperty source = propertyValue.Conditions[j].Property;\n\n                    // Check for obvious cycles.  Don't test for cycles if we have\n                    // something other than self as the target, since this means that\n                    // the templatedParent is presumably not the target.  See windows bug\n                    // 984916 for details.\n                    if (source == dependent && propertyValue.ChildName == StyleHelper.SelfName)\n                    {\n                        throw new InvalidOperationException(SR.Format(SR.PropertyTriggerCycleDetected, source.Name));\n                    }\n                }\n            }\n\n            _enterActions?.Seal(this);\n            _exitActions?.Seal(this);\n\n            // Remove thread affinity so it can be accessed across threads\n            DetachFromDispatcher();\n        }\n\n        // This will transfer information in the _setters collection to PropertyValues array.\n        internal void ProcessSettersCollection(SetterBaseCollection setters)\n        {\n            // Add information in Setters collection to PropertyValues array.\n            if( setters != null )\n            {\n                // Seal Setters","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/TriggerBase.cs#L229-L265","documentation":"During TriggerBase.Seal(), WPF detects a property-trigger cycle: a trigger's property value targets its own source element (source == dependent with ChildName == SelfName), which would cause infinite trigger re-evaluation. It throws InvalidOperationException (PropertyTriggerCycleDetected, source.Name) naming the offending element.","triggerScenarios":"A trigger in a template sets a property on the same element that the trigger's condition watches (self-referential TargetName/SelfName), e.g. a trigger on TemplateBinding-property X that sets X on the same node.","commonSituations":"Template authoring where a trigger's setter and condition reference the same property on the same element; refactoring templates and accidentally looping conditions.","solutions":["Retarget the trigger's Setter to a different element (use TargetName) or a different property","Break the cycle with an intermediate element or separate states (VisualStateManager)","Move the mutual dependency into a MultiTrigger/Converter that computes a stable value"],"exampleFix":"// before\n<Trigger Property=\"IsChecked\" Value=\"True\">\n  <Setter TargetName=\"self\" Property=\"IsChecked\" Value=\"False\"/>\n</Trigger>\n// after\n<!-- target a different property or element -->\n<Trigger Property=\"IsChecked\" Value=\"True\">\n  <Setter Property=\"Background\" Value=\"Green\"/>\n</Trigger>","handlingStrategy":"validation","validationCode":"if (triggerProperty == setterProperty && targetName == \"self\")\n    throw new InvalidOperationException(\"Trigger cycle detected.\");","typeGuard":null,"tryCatchPattern":"try { style.Seal(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"cycle\")) { /* fix trigger targeting */ }","preventionTips":["Never set the same property a trigger watches on the same element","Review template triggers for self-reference after refactoring","Use VisualStateManager for complex state transitions"],"tags":["wpf","templates","cycle-detection","infinite-loop"],"backgroundTag":"invalid-state-transition","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"}