{"record":{"id":"c7229003451368a0","repo":"AvaloniaUI/Avalonia","slug":"eventargstype-must-be-derived-from-routedeventargs","errorCode":null,"errorMessage":"eventArgsType must be derived from RoutedEventArgs.","messagePattern":"eventArgsType must be derived from RoutedEventArgs\\.","errorType":"exception","errorClass":"InvalidCastException","httpStatus":null,"severity":"error","filePath":"src/Avalonia.Base/Interactivity/RoutedEvent.cs","lineNumber":31,"sourceCode":"\n    public class RoutedEvent\n    {\n        private readonly LightweightSubject<(object, RoutedEventArgs)> _raised = new();\n        private readonly LightweightSubject<RoutedEventArgs> _routeFinished = new();\n\n        public RoutedEvent(\n            string name,\n            RoutingStrategies routingStrategies,\n            Type eventArgsType,\n            Type ownerType)\n        {\n            name = name ?? throw new ArgumentNullException(nameof(name));\n            eventArgsType = eventArgsType ?? throw new ArgumentNullException(nameof(name));\n            ownerType = ownerType ?? throw new ArgumentNullException(nameof(name));\n\n            if (!typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType))\n            {\n                throw new InvalidCastException(\"eventArgsType must be derived from RoutedEventArgs.\");\n            }\n\n            EventArgsType = eventArgsType;\n            Name = name;\n            OwnerType = ownerType;\n            RoutingStrategies = routingStrategies;\n        }\n\n        public Type EventArgsType { get; }\n\n        public string Name { get; }\n\n        public Type OwnerType { get; }\n\n        public RoutingStrategies RoutingStrategies { get; }\n\n        public bool HasRaisedSubscriptions => _raised.HasObservers;\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/AvaloniaUI/Avalonia/blob/11c542726898ae954a1ef668c65ec79ec92ab17d/src/Avalonia.Base/Interactivity/RoutedEvent.cs#L13-L49","documentation":"Thrown by the RoutedEvent constructor when the eventArgsType argument does not derive from RoutedEventArgs. RoutedEvent is the metadata object backing Avalonia's tunneling/bubbling routed-event system, and every routed event must carry strongly-typed EventArgs that inherit from RoutedEventArgs so the routing infrastructure can dispatch and cast them safely. Passing a non-derived Type (e.g. plain EventArgs, or a custom class that forgot the base) violates that contract at registration time.","triggerScenarios":"Calling `new RoutedEvent(name, routingStrategies, eventArgsType, ownerType)` or the `RoutedEvent.Register(...)` helper where `eventArgsType` is a Type that is not assignable to `typeof(RoutedEventArgs)`. Also fires if reflection or a generic registration helper forwards an unconstrained Type argument.","commonSituations":"Creating a custom routed event for a control and accidentally passing `typeof(EventArgs)` instead of a RoutedEventArgs-derived type. Copy-pasting a RoutedEvent.Register call and forgetting to update the generic/eventArgsType argument. Using an interop/event-args class from another framework that does not inherit from Avalonia's RoutedEventArgs.","solutions":["Change the eventArgsType to a class that derives from RoutedEventArgs (create a custom subclass if needed).","If using RoutedEvent.Register<TEventArgs>(...), ensure TEventArgs : RoutedEventArgs.","Verify the Type at the call site with typeof(RoutedEventArgs).IsAssignableFrom(eventArgsType) before registration."],"exampleFix":"// before\nvar evt = new RoutedEvent(\"Tap\", RoutingStrategies.Bubble, typeof(EventArgs), typeof(MyControl));\n\n// after\npublic class TapEventArgs : RoutedEventArgs { /* ... */ }\nvar evt = new RoutedEvent(\"Tap\", RoutingStrategies.Bubble, typeof(TapEventArgs), typeof(MyControl));","handlingStrategy":"type-guard","validationCode":"static bool IsRoutedEventArgsArgs(Type t) => typeof(RoutedEventArgs).IsAssignableFrom(t);\n\n// usage\nif (!IsRoutedEventArgsArgs(eventArgsType))\n    throw new InvalidOperationException($\"{eventArgsType} must derive from RoutedEventArgs.\");\nvar evt = new RoutedEvent(name, routingStrategies, eventArgsType, ownerType);","typeGuard":"// Prefer the generic registration helper which enforces the constraint at compile time:\n// RoutedEvent.Register<TEventArgs>(\"name\", RoutingStrategies.Bubble, typeof(Owner))\n// where TEventArgs : RoutedEventArgs\nstatic RoutedEvent RegisterSafe<TArgs>(string name, RoutingStrategies rs, Type owner)\n    where TArgs : RoutedEventArgs\n    => RoutedEvent.Register<TArgs>(name, rs, owner);","tryCatchPattern":null,"preventionTips":["Use the generic RoutedEvent.Register<TEventArgs> overload so the compiler enforces the RoutedEventArgs constraint.","If passing Type reflectively, validate with IsAssignableFrom before registration.","Keep all custom event-arg classes in a single folder inheriting from RoutedEventArgs to avoid copy-paste mistakes."],"tags":["routed-event","interactivity","type-validation","registration"],"backgroundTag":null,"analyzedSha":"11c542726898ae954a1ef668c65ec79ec92ab17d","analyzedAt":"2026-08-13T11:57:40.261Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}