{"record":{"id":"0423a61c00da975d","repo":"stride3d/stride","slug":"no-handler-was-previously-registered-for-this-dependency","errorCode":null,"errorMessage":"No handler was previously registered for this dependency property.","messagePattern":"No handler was previously registered for this dependency property\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/presentation/Stride.Core.Presentation.Wpf/Core/DependencyPropertyWatcher.cs","lineNumber":125,"sourceCode":"            DependencyPropertyDescriptor descriptor;\n            if (!descriptors.TryGetValue(property, out descriptor))\n            {\n                descriptor = DependencyPropertyDescriptor.FromProperty(property, AssociatedObject.GetType());\n                descriptors.Add(property, descriptor);\n            }\n            descriptor.AddValueChanged(AssociatedObject, handler);\n        }\n\n        private void DetachHandler([NotNull] DependencyProperty property, [NotNull] EventHandler handler)\n        {\n            if (property == null) throw new ArgumentNullException(nameof(property));\n            if (handler == null) throw new ArgumentNullException(nameof(handler));\n            if (frameworkElement == null) throw new InvalidOperationException(\"A dependency object must be attached in order to unregister a handler.\");\n\n            DependencyPropertyDescriptor descriptor;\n            if (!descriptors.TryGetValue(property, out descriptor))\n            {\n                throw new InvalidOperationException(\"No handler was previously registered for this dependency property.\");\n            }\n            descriptor.RemoveValueChanged(AssociatedObject, handler);\n        }\n\n        private void ElementLoaded(object sender, RoutedEventArgs e)\n        {\n            AttachHandlers();\n        }\n\n        private void ElementUnloaded(object sender, RoutedEventArgs e)\n        {\n            DetachHandlers();\n        }\n    }\n}\n","sourceCodeStart":107,"sourceCodeEnd":141,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/presentation/Stride.Core.Presentation.Wpf/Core/DependencyPropertyWatcher.cs#L107-L141","documentation":"DetachHandler looks up the DependencyPropertyDescriptor for the given property in the watcher's descriptor cache; if no descriptor exists, no handler was ever attached for that property and it throws InvalidOperationException 'No handler was previously registered for this dependency property.' The cache is populated only by AttachHandler, so a miss means no prior registration. Called by UnregisterValueChangedHander and DetachHandlers.","triggerScenarios":"Unregistering a handler for a property that was never registered; unregistering with a different DependencyProperty instance than the one used at registration; detaching twice (DetachHandlers already removed descriptors); registering on one watcher instance and unregistering on another.","commonSituations":"Cleanup code that unconditionally unregisters all properties including ones registration skipped; mismatched property constants between attach and detach code paths (e.g. TextBox.TextProperty vs a custom property); re-creating the watcher on reload and trying to unregister against the new instance.","solutions":["Only call UnregisterValueChangedHander for properties you previously registered on the same watcher instance.","Use the watcher's Detach/DetachHandlers bulk cleanup instead of per-property removal when tearing down.","Ensure the exact same DependencyProperty instance is used for attach and detach (share a static field).","Track registered properties in caller code and iterate that set during cleanup.","If unregistering may be redundant, wrap the call in a try-catch for InvalidOperationException and ignore this specific case."],"exampleFix":"// before\nwatcher.UnregisterValueChangedHander(SomeControl.VisibilityProperty, OnChanged); // never registered\n// after\nwatcher.RegisterValueChangedHandler(SomeControl.VisibilityProperty, OnChanged);\n// ... later, same watcher instance:\nwatcher.UnregisterValueChangedHander(SomeControl.VisibilityProperty, OnChanged);","handlingStrategy":"try-catch","validationCode":"if (!registeredProperties.Contains(property)) { log.Warn(\"Property was never registered on this watcher\"); return; }","typeGuard":"static bool WasRegistered(ISet<DependencyProperty> registered, DependencyProperty p) => registered?.Contains(p) == true;","tryCatchPattern":"try { watcher.UnregisterValueChangedHander(prop, handler); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"No handler was previously registered\")) { /* idempotent cleanup: ignore */ }","preventionTips":["Maintain a set of registered (property, handler) pairs in caller code.","Always use the same watcher instance for register and unregister.","Use Detach/DetachHandlers for teardown instead of per-property removal.","Share static DependencyProperty fields across attach/detach code paths."],"tags":["wpf","invalid-operation","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}