diff --git a/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs b/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs index fe7d937e..4aa2fbff 100644 --- a/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs +++ b/samples/BehaviorsTestApplication/ViewModels/MainWindowViewModel.cs @@ -10,27 +10,10 @@ public partial class MainWindowViewModel : ViewModelBase { private int _value; - [Reactive] - public partial int Count { get; set; } - - [Reactive] - public partial double Position { get; set; } - - [Reactive] - public partial ObservableCollection? Items { get; set; } - - public IObservable Values { get; } - - public ICommand InitializeCommand { get; set; } - - public ICommand MoveLeftCommand { get; set; } - - public ICommand MoveRightCommand { get; set; } - - public ICommand ResetMoveCommand { get; set; } - public MainWindowViewModel() { + PointerTriggersViewModel = new PointerTriggersViewModel(); + Count = 0; Position = 100.0; InitializeCommand = ReactiveCommand.Create(Initialize); @@ -93,6 +76,28 @@ public MainWindowViewModel() Values = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => _value++); } + [Reactive] + public partial PointerTriggersViewModel PointerTriggersViewModel { get; set; } + + [Reactive] + public partial int Count { get; set; } + + [Reactive] + public partial double Position { get; set; } + + [Reactive] + public partial ObservableCollection? Items { get; set; } + + public IObservable Values { get; } + + public ICommand InitializeCommand { get; set; } + + public ICommand MoveLeftCommand { get; set; } + + public ICommand MoveRightCommand { get; set; } + + public ICommand ResetMoveCommand { get; set; } + private void Initialize() { Console.WriteLine("InitializeCommand"); diff --git a/samples/BehaviorsTestApplication/ViewModels/PointerTriggersViewModel.cs b/samples/BehaviorsTestApplication/ViewModels/PointerTriggersViewModel.cs new file mode 100644 index 00000000..aa050a35 --- /dev/null +++ b/samples/BehaviorsTestApplication/ViewModels/PointerTriggersViewModel.cs @@ -0,0 +1,36 @@ +using System; +using System.Windows.Input; +using ReactiveUI; + +namespace BehaviorsTestApplication.ViewModels; + +public partial class PointerTriggersViewModel : ViewModelBase +{ + public PointerTriggersViewModel() + { + PointerPressedCommand = ReactiveCommand.Create<(double X, double Y)>(PointerPressed); + PointerReleasedCommand = ReactiveCommand.Create<(double X, double Y)>(PointerReleased); + PointerMovedCommand = ReactiveCommand.Create<(double X, double Y)>(PointerMoved); + } + + public ICommand PointerPressedCommand { get; set; } + + public ICommand PointerReleasedCommand { get; set; } + + public ICommand PointerMovedCommand { get; set; } + + private void PointerPressed((double X, double Y) point) + { + Console.WriteLine($"Pressed: {point}"); + } + + private void PointerReleased((double X, double Y) point) + { + Console.WriteLine($"Released: {point}"); + } + + private void PointerMoved((double X, double Y) point) + { + Console.WriteLine($"Moved: {point}"); + } +} diff --git a/samples/BehaviorsTestApplication/Views/MainView.axaml b/samples/BehaviorsTestApplication/Views/MainView.axaml index 963c7422..0201e86a 100644 --- a/samples/BehaviorsTestApplication/Views/MainView.axaml +++ b/samples/BehaviorsTestApplication/Views/MainView.axaml @@ -73,5 +73,8 @@ + + + diff --git a/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml b/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml new file mode 100644 index 00000000..ea6eb7f5 --- /dev/null +++ b/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml.cs b/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml.cs new file mode 100644 index 00000000..8cedf238 --- /dev/null +++ b/samples/BehaviorsTestApplication/Views/Pages/PointerTriggersView.axaml.cs @@ -0,0 +1,17 @@ +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace BehaviorsTestApplication.Views.Pages; + +public partial class PointerTriggersView : UserControl +{ + public PointerTriggersView() + { + InitializeComponent(); + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/samples/Directory.Packages.props b/samples/Directory.Packages.props index 63a3ff92..526b5278 100644 --- a/samples/Directory.Packages.props +++ b/samples/Directory.Packages.props @@ -13,7 +13,7 @@ - + diff --git a/src/Avalonia.Xaml.Interactions.Custom/Converters/PointerEventArgsConverter.cs b/src/Avalonia.Xaml.Interactions.Custom/Converters/PointerEventArgsConverter.cs new file mode 100644 index 00000000..dacf5ee9 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Converters/PointerEventArgsConverter.cs @@ -0,0 +1,85 @@ +using System; +using System.Globalization; +using Avalonia.Data.Converters; +using Avalonia.Input; + +namespace Avalonia.Xaml.Interactions.Custom.Converters; + +/// +/// Converter for . +/// +public class PointerEventArgsConverter : IValueConverter +{ + /// + /// Gets the instance of . + /// + public static readonly PointerEventArgsConverter Instance = new(); + + /// + public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + switch (value) + { + case PointerPressedEventArgs pointerPressedEventArgs: + { + if (pointerPressedEventArgs.Source is not Visual visual) + { + return AvaloniaProperty.UnsetValue; + } + + var (x, y) = pointerPressedEventArgs.GetPosition(visual); + + return (x, y); + } + case PointerReleasedEventArgs pointerReleasedEventArgs: + { + if (pointerReleasedEventArgs.Source is not Visual visual) + { + return AvaloniaProperty.UnsetValue; + } + + var (x, y) = pointerReleasedEventArgs.GetPosition(visual); + + return (x, y); + } + case PointerDeltaEventArgs pointerDeltaEventArgs: + { + var (x, y) = pointerDeltaEventArgs.Delta; + + return (x, y); + } + case PointerWheelEventArgs pointerWheelEventArgs: + { + var (x, y) = pointerWheelEventArgs.Delta; + + return (x, y); + } + case PointerEventArgs pointerEventArgs: + { + if (pointerEventArgs.Source is not Visual visual) + { + return AvaloniaProperty.UnsetValue; + } + + var (x, y) = pointerEventArgs.GetPosition(visual); + + return (x, y); + } + default: + return AvaloniaProperty.UnsetValue; + } + } + + /// + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + return AvaloniaProperty.UnsetValue; + } + + /// + /// + /// + /// + /// + public IValueConverter ProvideValue(IServiceProvider serviceProvider) => Instance; +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/ActualThemeVariantChangedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/ActualThemeVariantChangedTrigger.cs new file mode 100644 index 00000000..8b39af95 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/ActualThemeVariantChangedTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class ActualThemeVariantChangedTrigger : StyledElementTrigger +{ + /// + protected override void OnActualThemeVariantChangedEvent() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToLogicalTreeTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToLogicalTreeTrigger.cs new file mode 100644 index 00000000..e813943a --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToLogicalTreeTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class AttachedToLogicalTreeTrigger : StyledElementTrigger +{ + /// + protected override void OnAttachedToLogicalTree() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToVisualTreeTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToVisualTreeTrigger.cs new file mode 100644 index 00000000..45c8c3aa --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/AttachedToVisualTreeTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class AttachedToVisualTreeTrigger : StyledElementTrigger +{ + /// + protected override void OnAttachedToVisualTree() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/DataContextChangedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/DataContextChangedTrigger.cs new file mode 100644 index 00000000..cbb29ac9 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/DataContextChangedTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class DataContextChangedTrigger : StyledElementTrigger +{ + /// + protected override void OnDataContextChangedEvent() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromLogicalTreeTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromLogicalTreeTrigger.cs new file mode 100644 index 00000000..585ef130 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromLogicalTreeTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class DetachedFromLogicalTreeTrigger : StyledElementTrigger +{ + /// + protected override void OnDetachedFromLogicalTree() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromVisualTreeTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromVisualTreeTrigger.cs new file mode 100644 index 00000000..29321a76 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/DetachedFromVisualTreeTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class DetachedFromVisualTreeTrigger : StyledElementTrigger +{ + /// + protected override void OnDetachedFromVisualTree() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/InitializedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/InitializedTrigger.cs new file mode 100644 index 00000000..4618f50f --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/InitializedTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class InitializedTrigger : StyledElementTrigger +{ + /// + protected override void OnInitializedEvent() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/KeyDownTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/KeyDownTrigger.cs deleted file mode 100644 index 289a22b9..00000000 --- a/src/Avalonia.Xaml.Interactions.Custom/Core/KeyDownTrigger.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Reactive.Disposables; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.Xaml.Interactivity; - -namespace Avalonia.Xaml.Interactions.Custom; - -/// -/// -/// -public class KeyDownTrigger : RoutedEventTriggerBase -{ - /// - /// - /// - public static readonly StyledProperty KeyProperty = - AvaloniaProperty.Register(nameof(Key)); - - /// - /// - /// - public Key Key - { - get => GetValue(KeyProperty); - set => SetValue(KeyProperty, value); - } - - /// - /// - /// - public bool MarkAsHandled { get; set; } - - /// - /// - /// - /// - protected override void OnAttached(CompositeDisposable disposables) - { - if (AssociatedObject is InputElement element) - { - var disposable = element.AddDisposableHandler(InputElement.KeyDownEvent, OnKeyDown, EventRoutingStrategy); - disposables.Add(disposable); - } - } - - private void OnKeyDown(object? sender, KeyEventArgs e) - { - if (!IsEnabled) - { - return; - } - - if (e.Key == Key) - { - e.Handled = MarkAsHandled; - Interaction.ExecuteActions(AssociatedObject, Actions, null); - } - } -} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/LoadedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/LoadedTrigger.cs new file mode 100644 index 00000000..504f15c4 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/LoadedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Controls; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class LoadedTrigger : StyledElementTrigger +{ + /// + protected override void OnLoaded() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/ResourcesChangedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/ResourcesChangedTrigger.cs new file mode 100644 index 00000000..7094d8a4 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/ResourcesChangedTrigger.cs @@ -0,0 +1,20 @@ +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class ResourcesChangedTrigger : StyledElementTrigger +{ + /// + protected override void OnResourcesChangedEvent() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBase.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBase.cs index 79d185d3..70eca292 100644 --- a/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBase.cs +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBase.cs @@ -11,7 +11,7 @@ public abstract class RoutedEventTriggerBase : DisposingTrigger /// /// public static readonly StyledProperty EventRoutingStrategyProperty = - AvaloniaProperty.Register(nameof(EventRoutingStrategy)); + AvaloniaProperty.Register(nameof(EventRoutingStrategy), defaultValue: RoutingStrategies.Direct); /// /// @@ -21,4 +21,9 @@ public RoutingStrategies EventRoutingStrategy get => GetValue(EventRoutingStrategyProperty); set => SetValue(EventRoutingStrategyProperty, value); } + + /// + /// + /// + public bool MarkAsHandled { get; set; } } diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBaseOfT.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBaseOfT.cs new file mode 100644 index 00000000..c9c7832e --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/RoutedEventTriggerBaseOfT.cs @@ -0,0 +1,58 @@ +using System.Reactive.Disposables; +using Avalonia.Interactivity; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +/// +public abstract class RoutedEventTriggerBase : RoutedEventTriggerBase where T : RoutedEventArgs +{ + /// + /// + /// + protected abstract RoutedEvent RoutedEvent { get; } + + /// + /// + /// + /// + protected override void OnAttached(CompositeDisposable disposables) + { + if (AssociatedObject is Interactive interactive) + { + var disposable = interactive.AddDisposableHandler( + RoutedEvent, + Handler, + EventRoutingStrategy); + disposables.Add(disposable); + } + } + + /// + /// + /// + /// + /// + protected virtual void Handler(object? sender, T e) + { + if (!IsEnabled) + { + return; + } + + Execute(e); + } + + /// + /// + /// + /// + protected void Execute(T e) + { + e.Handled = MarkAsHandled; + Interaction.ExecuteActions(AssociatedObject, Actions, e); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Core/UnloadedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Core/UnloadedTrigger.cs new file mode 100644 index 00000000..85ccd9e6 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Core/UnloadedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Controls; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public abstract class UnloadedTrigger : StyledElementTrigger +{ + /// + protected override void OnUnloaded() + { + if (!IsEnabled) + { + return; + } + + Interaction.ExecuteActions(AssociatedObject, Actions, parameter: null); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/DoubleTappedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/DoubleTappedGestureTrigger.cs new file mode 100644 index 00000000..1a5d0802 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/DoubleTappedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class DoubleTappedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.DoubleTappedEvent; + + static DoubleTappedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/HoldingGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/HoldingGestureTrigger.cs new file mode 100644 index 00000000..6d345a62 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/HoldingGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class HoldingGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.HoldingEvent; + + static HoldingGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchEndedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchEndedGestureTrigger.cs new file mode 100644 index 00000000..aabd8cb9 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchEndedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PinchEndedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PinchEndedEvent; + + static PinchEndedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchGestureTrigger.cs new file mode 100644 index 00000000..825efabe --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PinchGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PinchGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PinchEvent; + + static PinchGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureMagnifyGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureMagnifyGestureTrigger.cs new file mode 100644 index 00000000..bd7447c3 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureMagnifyGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerTouchPadGestureMagnifyGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PointerTouchPadGestureMagnifyEvent; + + static PointerTouchPadGestureMagnifyGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureRotateGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureRotateGestureTrigger.cs new file mode 100644 index 00000000..60c2b12b --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureRotateGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerTouchPadGestureRotateGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PointerTouchPadGestureRotateEvent; + + static PointerTouchPadGestureRotateGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureSwipeGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureSwipeGestureTrigger.cs new file mode 100644 index 00000000..294cf9fa --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PointerTouchPadGestureSwipeGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerTouchPadGestureSwipeGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PointerTouchPadGestureSwipeEvent; + + static PointerTouchPadGestureSwipeGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureEndedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureEndedGestureTrigger.cs new file mode 100644 index 00000000..7ae9686a --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureEndedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PullGestureEndedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PullGestureEndedEvent; + + static PullGestureEndedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureGestureTrigger.cs new file mode 100644 index 00000000..819fda2d --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/PullGestureGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PullGestureGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.PullGestureEvent; + + static PullGestureGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/RightTappedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/RightTappedGestureTrigger.cs new file mode 100644 index 00000000..97c1aa9e --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/RightTappedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class RightTappedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.RightTappedEvent; + + static RightTappedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureEndedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureEndedGestureTrigger.cs new file mode 100644 index 00000000..1703e45c --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureEndedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class ScrollGestureEndedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.ScrollGestureEndedEvent; + + static ScrollGestureEndedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureGestureTrigger.cs new file mode 100644 index 00000000..959344c8 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class ScrollGestureGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.ScrollGestureEvent; + + static ScrollGestureGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureInertiaStartingGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureInertiaStartingGestureTrigger.cs new file mode 100644 index 00000000..c35f83b7 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/ScrollGestureInertiaStartingGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class ScrollGestureInertiaStartingGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.ScrollGestureInertiaStartingEvent; + + static ScrollGestureInertiaStartingGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Gestures/TappedGestureTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/Gestures/TappedGestureTrigger.cs new file mode 100644 index 00000000..a7d7b018 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/Gestures/TappedGestureTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class TappedGestureTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => Gestures.TappedEvent; + + static TappedGestureTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/CapturePointerAction.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/CapturePointerAction.cs new file mode 100644 index 00000000..5c54b2f2 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/CapturePointerAction.cs @@ -0,0 +1,52 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// Captures the pointer. +/// +public class CapturePointerAction : StyledElementAction +{ + /// + /// Identifies the avalonia property. + /// + public static readonly StyledProperty TargetControlProperty = + AvaloniaProperty.Register(nameof(TargetControl)); + + /// + /// Gets or sets the target control. This is an avalonia property. + /// + [ResolveByName] + public Control? TargetControl + { + get => GetValue(TargetControlProperty); + set => SetValue(TargetControlProperty, value); + } + + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// Returns null after executed. + public override object? Execute(object? sender, object? parameter) + { + if (parameter is not PointerEventArgs pointerEventArgs) + { + return null; + } + + if (pointerEventArgs.Source is not IInputElement inputElement) + { + return null; + } + + var control = TargetControl ?? inputElement; + + pointerEventArgs.Pointer.Capture(control); + + return null; + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/ReleasePointerCaptureAction.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/ReleasePointerCaptureAction.cs new file mode 100644 index 00000000..f3141224 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Actions/ReleasePointerCaptureAction.cs @@ -0,0 +1,33 @@ +using Avalonia.Input; +using Avalonia.Xaml.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// Releases the pointer capture. +/// +public class ReleasePointerCaptureAction : StyledElementAction +{ + /// + /// Executes the action. + /// + /// The that is passed to the action by the behavior. Generally this is or a target object. + /// The value of this parameter is determined by the caller. + /// Returns null after executed. + public override object? Execute(object? sender, object? parameter) + { + if (parameter is not PointerEventArgs pointerEventArgs) + { + return null; + } + + if (pointerEventArgs.Source is not IInputElement) + { + return null; + } + + pointerEventArgs.Pointer.Capture(control: null); + + return null; + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/DoubleTappedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/DoubleTappedTrigger.cs new file mode 100644 index 00000000..4e436ff8 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/DoubleTappedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class DoubleTappedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.DoubleTappedEvent; + + static DoubleTappedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/GotFocusTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/GotFocusTrigger.cs new file mode 100644 index 00000000..05fa2a5a --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/GotFocusTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class GotFocusTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.GotFocusEvent; + + static GotFocusTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/HoldingTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/HoldingTrigger.cs new file mode 100644 index 00000000..e2a423f9 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/HoldingTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class HoldingTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.HoldingEvent; + + static HoldingTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyDownTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyDownTrigger.cs new file mode 100644 index 00000000..1d8e93b6 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyDownTrigger.cs @@ -0,0 +1,67 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class KeyDownTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.KeyDownEvent; + + /// + /// + /// + public static readonly StyledProperty KeyProperty = + AvaloniaProperty.Register(nameof(Key)); + + /// + /// + /// + public static readonly StyledProperty GestureProperty = + AvaloniaProperty.Register(nameof(Gesture)); + + /// + /// + /// + public Key? Key + { + get => GetValue(KeyProperty); + set => SetValue(KeyProperty, value); + } + + /// + /// + /// + public KeyGesture? Gesture + { + get => GetValue(GestureProperty); + set => SetValue(GestureProperty, value); + } + + /// + protected override void Handler(object? sender, KeyEventArgs e) + { + if (!IsEnabled) + { + return; + } + + var isKeySet = IsSet(KeyProperty); + var isGestureSet = IsSet(GestureProperty); + var key = Key; + var gesture = Gesture; + var haveKey = key is not null && isKeySet && e.Key == key; + var haveGesture = gesture is not null && isGestureSet && gesture.Matches(e); + + if ((!isKeySet && !isGestureSet) + || haveKey + || haveGesture) + { + Execute(e); + } + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyUpTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyUpTrigger.cs new file mode 100644 index 00000000..1b59ccd4 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/KeyUpTrigger.cs @@ -0,0 +1,67 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class KeyUpTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.KeyUpEvent; + + /// + /// + /// + public static readonly StyledProperty KeyProperty = + AvaloniaProperty.Register(nameof(Key)); + + /// + /// + /// + public static readonly StyledProperty GestureProperty = + AvaloniaProperty.Register(nameof(Gesture)); + + /// + /// + /// + public Key? Key + { + get => GetValue(KeyProperty); + set => SetValue(KeyProperty, value); + } + + /// + /// + /// + public KeyGesture? Gesture + { + get => GetValue(GestureProperty); + set => SetValue(GestureProperty, value); + } + + /// + protected override void Handler(object? sender, KeyEventArgs e) + { + if (!IsEnabled) + { + return; + } + + var isKeySet = IsSet(KeyProperty); + var isGestureSet = IsSet(GestureProperty); + var key = Key; + var gesture = Gesture; + var haveKey = key is not null && isKeySet && e.Key == key; + var haveGesture = gesture is not null && isGestureSet && gesture.Matches(e); + + if ((!isKeySet && !isGestureSet) + || haveKey + || haveGesture) + { + Execute(e); + } + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/LostFocusTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/LostFocusTrigger.cs new file mode 100644 index 00000000..82ae8ad9 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/LostFocusTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class LostFocusTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.LostFocusEvent; + + static LostFocusTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerCaptureLostTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerCaptureLostTrigger.cs new file mode 100644 index 00000000..d1382a7d --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerCaptureLostTrigger.cs @@ -0,0 +1,14 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerCaptureLostTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerCaptureLostEvent; +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerEnteredTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerEnteredTrigger.cs new file mode 100644 index 00000000..2f872b57 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerEnteredTrigger.cs @@ -0,0 +1,14 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerEnteredTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerEnteredEvent; +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerExitedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerExitedTrigger.cs new file mode 100644 index 00000000..3166180f --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerExitedTrigger.cs @@ -0,0 +1,14 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerExitedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerExitedEvent; +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerMovedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerMovedTrigger.cs new file mode 100644 index 00000000..f8318b3e --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerMovedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerMovedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerMovedEvent; + + static PointerMovedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerPressedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerPressedTrigger.cs new file mode 100644 index 00000000..dc425901 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerPressedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerPressedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerPressedEvent; + + static PointerPressedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerReleasedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerReleasedTrigger.cs new file mode 100644 index 00000000..952c7f81 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerReleasedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerReleasedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerReleasedEvent; + + static PointerReleasedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerWheelChangedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerWheelChangedTrigger.cs new file mode 100644 index 00000000..606c919f --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/PointerWheelChangedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class PointerWheelChangedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.PointerWheelChangedEvent; + + static PointerWheelChangedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TappedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TappedTrigger.cs new file mode 100644 index 00000000..bb3901a4 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TappedTrigger.cs @@ -0,0 +1,21 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class TappedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.TappedEvent; + + static TappedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputMethodClientRequestedTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputMethodClientRequestedTrigger.cs new file mode 100644 index 00000000..04af61f0 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputMethodClientRequestedTrigger.cs @@ -0,0 +1,22 @@ +using Avalonia.Input; +using Avalonia.Input.TextInput; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class TextInputMethodClientRequestedTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.TextInputMethodClientRequestedEvent; + + static TextInputMethodClientRequestedTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputTrigger.cs b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputTrigger.cs new file mode 100644 index 00000000..6f7ca055 --- /dev/null +++ b/src/Avalonia.Xaml.Interactions.Custom/InputElement/Triggers/TextInputTrigger.cs @@ -0,0 +1,54 @@ +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Xaml.Interactions.Custom; + +/// +/// +/// +public class TextInputTrigger : RoutedEventTriggerBase +{ + /// + protected override RoutedEvent RoutedEvent + => InputElement.TextInputEvent; + + static TextInputTrigger() + { + EventRoutingStrategyProperty.OverrideMetadata( + new StyledPropertyMetadata( + defaultValue: RoutingStrategies.Tunnel | RoutingStrategies.Bubble)); + } + + /// + /// + /// + public static readonly StyledProperty TextProperty = + AvaloniaProperty.Register(nameof(Text)); + + /// + /// + /// + public string? Text + { + get => GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + /// + protected override void Handler(object? sender, TextInputEventArgs e) + { + if (!IsEnabled) + { + return; + } + + var isTextSet = IsSet(TextProperty); + var text = Text; + var haveText = isTextSet && e.Text == text; + + if (!isTextSet || haveText) + { + Execute(e); + } + } +} diff --git a/src/Avalonia.Xaml.Interactions.Custom/Properties/AssemblyInfo.cs b/src/Avalonia.Xaml.Interactions.Custom/Properties/AssemblyInfo.cs index 8be27f20..7d57de57 100644 --- a/src/Avalonia.Xaml.Interactions.Custom/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Xaml.Interactions.Custom/Properties/AssemblyInfo.cs @@ -4,3 +4,5 @@ [assembly: InternalsVisibleTo("Avalonia.Xaml.Interactions.UnitTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001002940ed211918fcf63c506fad1d3f7f958b21ff8f06fd2089398296173f9ca93a69b9b380a828bf13fa80d1745beeb917ec3692f4d10e44b4c941619fc7bbd5052b26880697e6fa3f0ce322c4fa902d20b67a48b4144371218f6d39ad39145ea1fe5484052dd51a2ee62af3acd0759bcf92aaefec03978ded3cfaa84798e92de8")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Custom")] + +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Custom.Converters")] diff --git a/src/Xaml.Behaviors/Properties/AssemblyInfo.cs b/src/Xaml.Behaviors/Properties/AssemblyInfo.cs index 15c093ea..80daad25 100644 --- a/src/Xaml.Behaviors/Properties/AssemblyInfo.cs +++ b/src/Xaml.Behaviors/Properties/AssemblyInfo.cs @@ -8,6 +8,7 @@ [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Core")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Custom")] +[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Custom.Converters")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.DragAndDrop")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Draggable")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Xaml.Interactions.Events")]