using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Reactive; using Avalonia.Xaml.Interactivity; namespace Avalonia.Xaml.Interactions.Custom; /// /// A behavior that listens for a event on its source and executes its actions when that event is fired. /// public class RoutedEventTriggerBehavior : StyledElementTrigger { /// /// Identifies the avalonia property. /// public static readonly StyledProperty RoutedEventProperty = AvaloniaProperty.Register(nameof(RoutedEvent)); /// /// Identifies the avalonia property. /// public static readonly StyledProperty RoutingStrategiesProperty = AvaloniaProperty.Register(nameof(RoutingStrategies), RoutingStrategies.Direct | RoutingStrategies.Bubble); /// /// Identifies the avalonia property. /// public static readonly StyledProperty SourceInteractiveProperty = AvaloniaProperty.Register(nameof(SourceInteractive)); private bool _isInitialized; private bool _isAttached; /// /// Gets or sets routing event to listen for. This is a avalonia property. /// public RoutedEvent? RoutedEvent { get => GetValue(RoutedEventProperty); set => SetValue(RoutedEventProperty, value); } /// /// Gets or sets the routing event . This is a avalonia property. /// public RoutingStrategies RoutingStrategies { get => GetValue(RoutingStrategiesProperty); set => SetValue(RoutingStrategiesProperty, value); } /// /// Gets or sets the source object from which this behavior listens for events. /// If is not set, the source will default to . This is a avalonia property. /// [ResolveByName] public Interactive? SourceInteractive { get => GetValue(SourceInteractiveProperty); set => SetValue(SourceInteractiveProperty, value); } static RoutedEventTriggerBehavior() { RoutedEventProperty.Changed.Subscribe( new AnonymousObserver>(OnValueChanged)); RoutingStrategiesProperty.Changed.Subscribe( new AnonymousObserver>(OnValueChanged)); SourceInteractiveProperty.Changed.Subscribe( new AnonymousObserver>(OnValueChanged)); } private static void OnValueChanged(AvaloniaPropertyChangedEventArgs args) { if (args.Sender is not RoutedEventTriggerBehavior behavior || behavior.AssociatedObject is null) { return; } if (behavior._isInitialized && behavior._isAttached) { behavior.RemoveHandler(); behavior.AddHandler(); } } /// protected override void OnAttachedToVisualTree() { _isAttached = true; AddHandler(); } /// protected override void OnDetachedFromVisualTree() { _isAttached = false; RemoveHandler(); } private void AddHandler() { var interactive = ComputeResolvedSourceInteractive(); if (interactive is not null && RoutedEvent is not null) { interactive.AddHandler(RoutedEvent, Handler, RoutingStrategies); _isInitialized = true; } } private void RemoveHandler() { var interactive = ComputeResolvedSourceInteractive(); if (interactive is not null && RoutedEvent is not null && _isInitialized) { interactive.RemoveHandler(RoutedEvent, Handler); _isInitialized = false; } } private Interactive? ComputeResolvedSourceInteractive() { return GetValue(SourceInteractiveProperty) is not null ? SourceInteractive : AssociatedObject; } private void Handler(object? sender, RoutedEventArgs e) { if (!IsEnabled) { return; } var interactive = ComputeResolvedSourceInteractive(); if (interactive is not null) { Interaction.ExecuteActions(interactive, Actions, e); } } }