This commit is contained in:
Wiesław Šoltés 2024-04-24 13:23:09 +02:00
Родитель 218ec6bfdb
Коммит fea28a56bc
34 изменённых файлов: 1306 добавлений и 133 удалений

Просмотреть файл

@ -11,7 +11,7 @@
<Panel Background="Transparent">
<i:Interaction.Behaviors>
<iac:ShowOnDoubleTappedBehavior TargetControl="TextBoxEdit" />
<iac:ShowOnKeyDownTappedBehavior TargetControl="TextBoxEdit" />
<iac:ShowOnKeyDownBehavior TargetControl="TextBoxEdit" Key="F2" />
</i:Interaction.Behaviors>
<TextBox x:Name="TextBoxEdit"
IsVisible="False"

Просмотреть файл

@ -11,12 +11,6 @@ namespace Avalonia.Xaml.Interactions.Custom;
/// </summary>
public class ButtonExecuteCommandOnKeyDownBehavior : AttachedToVisualTreeBehavior<Button>
{
/// <summary>
///
/// </summary>
public static readonly StyledProperty<Key?> KeyProperty =
AvaloniaProperty.Register<ButtonExecuteCommandOnKeyDownBehavior, Key?>(nameof(Key));
/// <summary>
///
/// </summary>
@ -26,11 +20,14 @@ public class ButtonExecuteCommandOnKeyDownBehavior : AttachedToVisualTreeBehavio
/// <summary>
///
/// </summary>
public Key? Key
{
get => GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}
public static readonly StyledProperty<Key?> KeyProperty =
AvaloniaProperty.Register<ButtonExecuteCommandOnKeyDownBehavior, Key?>(nameof(Key));
/// <summary>
///
/// </summary>
public static readonly StyledProperty<KeyGesture?> GestureProperty =
AvaloniaProperty.Register<ButtonExecuteCommandOnKeyDownBehavior, KeyGesture?>(nameof(Gesture));
/// <summary>
///
@ -41,19 +38,31 @@ public class ButtonExecuteCommandOnKeyDownBehavior : AttachedToVisualTreeBehavio
set => SetValue(IsEnabledProperty, value);
}
/// <summary>
///
/// </summary>
public Key? Key
{
get => GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}
/// <summary>
///
/// </summary>
public KeyGesture? Gesture
{
get => GetValue(GestureProperty);
set => SetValue(GestureProperty, value);
}
/// <summary>
///
/// </summary>
/// <param name="disposables"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposables)
{
var button = AssociatedObject;
if (button is null)
{
return;
}
if (button.GetVisualRoot() is InputElement inputRoot)
if (AssociatedObject?.GetVisualRoot() is InputElement inputRoot)
{
var disposable = inputRoot.AddDisposableHandler(InputElement.KeyDownEvent, RootDefaultKeyDown);
disposables.Add(disposable);
@ -62,19 +71,38 @@ public class ButtonExecuteCommandOnKeyDownBehavior : AttachedToVisualTreeBehavio
private void RootDefaultKeyDown(object? sender, KeyEventArgs e)
{
var button = AssociatedObject;
if (button is null)
var haveKey = Key is not null && e.Key == Key;
var haveGesture = Gesture is not null && Gesture.Matches(e);
if (!haveKey && !haveGesture)
{
return;
}
if (Key is { } && e.Key == Key && button.IsVisible && button.IsEnabled && IsEnabled)
if (AssociatedObject is { } button)
{
if (!e.Handled && button.Command?.CanExecute(button.CommandParameter) == true)
{
button.Command.Execute(button.CommandParameter);
e.Handled = true;
}
ExecuteCommand(button);
}
}
private bool ExecuteCommand(Button button)
{
if (!IsEnabled)
{
return false;
}
if (button is not { IsVisible: true, IsEnabled: true })
{
return false;
}
if (button.Command?.CanExecute(button.CommandParameter) != true)
{
return false;
}
button.Command.Execute(button.CommandParameter);
return true;
}
}

Просмотреть файл

@ -10,6 +10,12 @@ namespace Avalonia.Xaml.Interactions.Custom;
/// </summary>
public abstract class ExecuteCommandBehaviorBase : AttachedToVisualTreeBehavior<Control>
{
/// <summary>
///
/// </summary>
public static readonly StyledProperty<bool> IsEnabledProperty =
AvaloniaProperty.Register<ExecuteCommandBehaviorBase, bool>(nameof(IsEnabled), true);
/// <summary>
///
/// </summary>
@ -34,6 +40,15 @@ public abstract class ExecuteCommandBehaviorBase : AttachedToVisualTreeBehavior<
public static readonly StyledProperty<Control?> FocusControlProperty =
AvaloniaProperty.Register<ExecuteCommandBehaviorBase, Control?>(nameof(CommandParameter));
/// <summary>
///
/// </summary>
public bool IsEnabled
{
get => GetValue(IsEnabledProperty);
set => SetValue(IsEnabledProperty, value);
}
/// <summary>
///
/// </summary>
@ -77,6 +92,11 @@ public abstract class ExecuteCommandBehaviorBase : AttachedToVisualTreeBehavior<
/// <returns></returns>
protected bool ExecuteCommand()
{
if (!IsEnabled)
{
return false;
}
if (AssociatedObject is not { IsVisible: true, IsEnabled: true })
{
return false;

Просмотреть файл

@ -20,13 +20,16 @@ public class ExecuteCommandOnActivatedBehavior : ExecuteCommandBehaviorBase
{
var mainWindow = lifetime.MainWindow;
var dispose = Observable
.FromEventPattern(mainWindow, nameof(mainWindow.Activated))
.Subscribe(new AnonymousObserver<EventPattern<object>>(e =>
{
ExecuteCommand();
}));
disposable.Add(dispose);
if (mainWindow is not null)
{
var dispose = Observable
.FromEventPattern(mainWindow, nameof(mainWindow.Activated))
.Subscribe(new AnonymousObserver<EventPattern<object>>(e =>
{
ExecuteCommand();
}));
disposable.Add(dispose);
}
}
}
}

Просмотреть файл

@ -40,4 +40,3 @@ public class ExecuteCommandOnDoubleTappedBehavior : ExecuteCommandBehaviorBase
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnGotFocusBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.GotFocusEvent,
AssociatedObject_GotFocus,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_GotFocus(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnHoldingBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.HoldingEvent,
AssociatedObject_Holding,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_Holding(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -78,3 +78,78 @@ public class ExecuteCommandOnKeyDownBehavior : ExecuteCommandBehaviorBase
}
}
}
/// <summary>
///
/// </summary>
public class ExecuteCommandOnKeyUpBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
public static readonly StyledProperty<Key?> KeyProperty =
AvaloniaProperty.Register<ExecuteCommandOnKeyDownBehavior, Key?>(nameof(Key));
/// <summary>
///
/// </summary>
public static readonly StyledProperty<KeyGesture?> GestureProperty =
AvaloniaProperty.Register<ExecuteCommandOnKeyDownBehavior, KeyGesture?>(nameof(Gesture));
/// <summary>
///
/// </summary>
public Key? Key
{
get => GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}
/// <summary>
///
/// </summary>
public KeyGesture? Gesture
{
get => GetValue(GestureProperty);
set => SetValue(GestureProperty, value);
}
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.KeyUpEvent,
OnKeyUp,
RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void OnKeyUp(object? sender, KeyEventArgs e)
{
var haveKey = Key is not null && e.Key == Key;
var haveGesture = Gesture is not null && Gesture.Matches(e);
if (!haveKey && !haveGesture)
{
return;
}
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPinchBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PinchEvent,
AssociatedObject_Pinch,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_Pinch(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPinchEndedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PinchEndedEvent,
AssociatedObject_PinchEnded,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PinchEnded(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerCaptureLostBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerCaptureLostEvent,
AssociatedObject_PointerCaptureLost,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerCaptureLost(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerEnteredBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerEnteredEvent,
AssociatedObject_PointerEntered,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerEntered(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerExitedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerExitedEvent,
AssociatedObject_PointerExited,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerExited(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerMovedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerMovedEvent,
AssociatedObject_PointerMoved,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerMoved(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerPressedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerPressedEvent,
AssociatedObject_PointerPressed,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerPressed(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerReleasedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerReleasedEvent,
AssociatedObject_PointerReleased,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerReleased(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerTouchPadGestureMagnifyBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PointerTouchPadGestureMagnifyEvent,
AssociatedObject_PointerTouchPadGestureMagnify,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerTouchPadGestureMagnify(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerTouchPadGestureRotateBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PointerTouchPadGestureRotateEvent,
AssociatedObject_PointerTouchPadGestureRotate,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerTouchPadGestureRotate(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerTouchPadGestureSwipeBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PointerTouchPadGestureSwipeEvent,
AssociatedObject_PointerTouchPadGestureSwipe,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerTouchPadGestureSwipe(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPointerWheelChangedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.PointerWheelChangedEvent,
AssociatedObject_PointerWheelChanged,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PointerWheelChanged(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPullGestureBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PullGestureEvent,
AssociatedObject_PullGesture,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PullGesture(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnPullGestureEndedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.PullGestureEndedEvent,
AssociatedObject_PullGestureEnded,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_PullGestureEnded(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnRightTappedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.RightTappedEvent,
AssociatedObject_RightTapped,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_RightTapped(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnScrollGestureBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.ScrollGestureEvent,
AssociatedObject_ScrollGesture,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_ScrollGesture(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnScrollGestureEndedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.ScrollGestureEndedEvent,
AssociatedObject_ScrollGestureEnded,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_ScrollGestureEnded(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnScrollGestureInertiaStartingBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.ScrollGestureInertiaStartingEvent,
AssociatedObject_ScrollGestureInertiaStarting,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_ScrollGestureInertiaStarting(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnTappedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.TappedEvent,
AssociatedObject_Tapped,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_Tapped(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnTextInputBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.TextInputEvent,
AssociatedObject_TextInput,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_TextInput(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public class ExecuteCommandOnTextInputMethodClientRequestedBehavior : ExecuteCommandBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.TextInputMethodClientRequestedEvent,
AssociatedObject_TextInputMethodClientRequested,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_TextInputMethodClientRequested(object? sender, RoutedEventArgs e)
{
if (e.Handled)
{
return;
}
if (ExecuteCommand())
{
e.Handled = true;
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
using Avalonia.Controls;
using Avalonia.Threading;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
///
/// </summary>
public abstract class ShowBehaviorBase : AttachedToVisualTreeBehavior<Control>
{
/// <summary>
///
/// </summary>
public static readonly StyledProperty<bool> IsEnabledProperty =
AvaloniaProperty.Register<ShowBehaviorBase, bool>(nameof(IsEnabled), true);
/// <summary>
/// Identifies the <seealso cref="TargetControl"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Control?> TargetControlProperty =
AvaloniaProperty.Register<ShowBehaviorBase, Control?>(nameof(TargetControl));
/// <summary>
///
/// </summary>
public bool IsEnabled
{
get => GetValue(IsEnabledProperty);
set => SetValue(IsEnabledProperty, value);
}
/// <summary>
/// Gets or sets the target control. This is a avalonia property.
/// </summary>
[ResolveByName]
public Control? TargetControl
{
get => GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
protected bool Show()
{
if (IsEnabled && TargetControl is { IsVisible: false })
{
TargetControl.SetCurrentValue(Visual.IsVisibleProperty, true);
Dispatcher.UIThread.Post(() => TargetControl.Focus());
return true;
}
return false;
}
}

Просмотреть файл

@ -1,51 +1,34 @@
using Avalonia.Controls;
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.Xaml.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
/// A behavior that allows to show control on double tapped event.
/// </summary>
public class ShowOnDoubleTappedBehavior : Behavior<Control>
public class ShowOnDoubleTappedBehavior : ShowBehaviorBase
{
/// <summary>
/// Identifies the <seealso cref="TargetControl"/> avalonia property.
///
/// </summary>
public static readonly StyledProperty<Control?> TargetControlProperty =
AvaloniaProperty.Register<ShowOnDoubleTappedBehavior, Control?>(nameof(TargetControl));
/// <summary>
/// Gets or sets the target control. This is a avalonia property.
/// </summary>
[ResolveByName]
public Control? TargetControl
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
get => GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.DoubleTappedEvent,
AssociatedObject_DoubleTapped,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
/// <inheritdoc />
protected override void OnAttachedToVisualTree()
{
AssociatedObject?.AddHandler(Gestures.DoubleTappedEvent, AssociatedObject_DoubleTapped,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
}
/// <inheritdoc />
protected override void OnDetachedFromVisualTree()
{
AssociatedObject?.RemoveHandler(Gestures.DoubleTappedEvent, AssociatedObject_DoubleTapped);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_DoubleTapped(object? sender, RoutedEventArgs e)
{
if (TargetControl is {IsVisible: false})
{
TargetControl.IsVisible = true;
Dispatcher.UIThread.Post(() => TargetControl.Focus());
}
Show();
}
}

Просмотреть файл

@ -0,0 +1,72 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
/// A behavior that allows to show control on key down event.
/// </summary>
public class ShowOnKeyDownBehavior : ShowBehaviorBase
{
/// <summary>
/// Identifies the <seealso cref="Key"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Key?> KeyProperty =
AvaloniaProperty.Register<ShowOnKeyDownBehavior, Key?>(nameof(Key));
/// <summary>
///
/// </summary>
public static readonly StyledProperty<KeyGesture?> GestureProperty =
AvaloniaProperty.Register<ShowOnKeyDownBehavior, KeyGesture?>(nameof(Gesture));
/// <summary>
/// Gets or sets the key. This is a avalonia property.
/// </summary>
public Key? Key
{
get => GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}
/// <summary>
///
/// </summary>
public KeyGesture? Gesture
{
get => GetValue(GestureProperty);
set => SetValue(GestureProperty, value);
}
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
InputElement.KeyDownEvent,
AssociatedObject_KeyDown,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_KeyDown(object? sender, KeyEventArgs e)
{
var haveKey = Key is not null && e.Key == Key;
var haveGesture = Gesture is not null && Gesture.Matches(e);
if (!haveKey && !haveGesture)
{
return;
}
Show();
}
}

Просмотреть файл

@ -1,66 +0,0 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Avalonia.Xaml.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
/// A behavior that allows to show control on key down event.
/// </summary>
public class ShowOnKeyDownTappedBehavior : Behavior<Control>
{
/// <summary>
/// Identifies the <seealso cref="TargetControl"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Control?> TargetControlProperty =
AvaloniaProperty.Register<ShowOnKeyDownTappedBehavior, Control?>(nameof(TargetControl));
/// <summary>
/// Identifies the <seealso cref="Key"/> avalonia property.
/// </summary>
public static readonly StyledProperty<Key> KeyProperty =
AvaloniaProperty.Register<ShowOnKeyDownTappedBehavior, Key>(nameof(Key), Key.F2);
/// <summary>
/// Gets or sets the target control. This is a avalonia property.
/// </summary>
[ResolveByName]
public Control? TargetControl
{
get => GetValue(TargetControlProperty);
set => SetValue(TargetControlProperty, value);
}
/// <summary>
/// Gets or sets the key. This is a avalonia property.
/// </summary>
public Key Key
{
get => GetValue(KeyProperty);
set => SetValue(KeyProperty, value);
}
/// <inheritdoc />
protected override void OnAttachedToVisualTree()
{
AssociatedObject?.AddHandler(InputElement.KeyDownEvent, AssociatedObject_KeyDown,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
}
/// <inheritdoc />
protected override void OnDetachedFromVisualTree()
{
AssociatedObject?.RemoveHandler(InputElement.KeyDownEvent, AssociatedObject_KeyDown);
}
private void AssociatedObject_KeyDown(object? sender, KeyEventArgs e)
{
if (e.Key == Key && TargetControl is {IsVisible: false})
{
TargetControl.IsVisible = true;
Dispatcher.UIThread.Post(() => TargetControl.Focus());
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System.Reactive.Disposables;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Xaml.Interactions.Custom;
/// <summary>
/// A behavior that allows to show control on tapped event.
/// </summary>
public class ShowOnTappedBehavior : ShowBehaviorBase
{
/// <summary>
///
/// </summary>
/// <param name="disposable"></param>
protected override void OnAttachedToVisualTree(CompositeDisposable disposable)
{
var dispose = AssociatedObject?
.AddDisposableHandler(
Gestures.TappedEvent,
AssociatedObject_Tapped,
RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
if (dispose is not null)
{
disposable.Add(dispose);
}
}
private void AssociatedObject_Tapped(object? sender, RoutedEventArgs e)
{
Show();
}
}