Skip to content
This repository has been archived by the owner on Nov 1, 2024. It is now read-only.

Example for Shift+Click or Control+Click button? #73

Closed
derekantrican opened this issue Jul 15, 2021 · 4 comments
Closed

Example for Shift+Click or Control+Click button? #73

derekantrican opened this issue Jul 15, 2021 · 4 comments

Comments

@derekantrican
Copy link

Is there an example for shift+clicking or ctrl+clicking a button? I want my button to have one command, but if I shift+click the button I want it to invoke a different command

@wieslawsoltes
Copy link
Contributor

I don't know any built-in way to do that.

I suppose one can create custom action based on InvokeCommandAction for button with check for key gesture.

@wieslawsoltes
Copy link
Contributor

wieslawsoltes commented Jul 15, 2021

@derekantrican

Custom behavior for your use case (will be available in next release under Avalonia.Xaml.Interactions.Custom namespace as ButtonClickEventTriggerBehavior from Avalonia.Xaml.Interactions NuGet package.

ButtonClickEventTriggerBehavior.cs

using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;

namespace Avalonia.Xaml.Interactions.Custom
{
    /// <summary>
    /// A behavior that listens for a <see cref="Button.ClickEvent"/> event on its source and executes its actions when that event is fired.
    /// </summary>
    public class ButtonClickEventTriggerBehavior : Trigger<Button>
    {
        private KeyModifiers _savedKeyModifiers = KeyModifiers.None;

        /// <summary>
        /// Identifies the <seealso cref="KeyModifiers"/> avalonia property.
        /// </summary>
        public static readonly StyledProperty<KeyModifiers> KeyModifiersProperty =
            AvaloniaProperty.Register<ButtonClickEventTriggerBehavior, KeyModifiers>(nameof(KeyModifiers));

        /// <summary>
        /// Gets or sets the required key modifiers to execute <see cref="Button.ClickEvent"/> event handler. This is a avalonia property.
        /// </summary>
        public KeyModifiers KeyModifiers
        {
            get => GetValue(KeyModifiersProperty);
            set => SetValue(KeyModifiersProperty, value);
        }

        /// <summary>
        /// Called after the behavior is attached to the <see cref="Behavior.AssociatedObject"/>.
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

            if (AssociatedObject is { })
            {
                AssociatedObject.Click += AssociatedObject_OnClick;
                AssociatedObject.AddHandler(InputElement.KeyDownEvent, Button_OnKeyDown, RoutingStrategies.Tunnel);
                AssociatedObject.AddHandler(InputElement.KeyUpEvent, Button_OnKeyUp, RoutingStrategies.Tunnel);
            }
        }

        /// <summary>
        /// Called when the behavior is being detached from its <see cref="Behavior.AssociatedObject"/>.
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            if (AssociatedObject is { })
            {
                AssociatedObject.Click -= AssociatedObject_OnClick;
                AssociatedObject.RemoveHandler(InputElement.KeyDownEvent, Button_OnKeyDown);
                AssociatedObject.RemoveHandler(InputElement.KeyUpEvent, Button_OnKeyUp);
            }
        }

        private void AssociatedObject_OnClick(object sender, RoutedEventArgs e)
        {
            if (AssociatedObject is { } && KeyModifiers == _savedKeyModifiers)
            {
                Interaction.ExecuteActions(AssociatedObject, Actions, e);
            }
        }

        private void Button_OnKeyDown(object sender, KeyEventArgs e)
        {
            _savedKeyModifiers = e.KeyModifiers;
        }

        private void Button_OnKeyUp(object sender, KeyEventArgs e)
        {
            _savedKeyModifiers = KeyModifiers.None;
        }
    }
}

Example usage:

<UserControl x:Class="BehaviorsTestApplication.Views.Pages.ButtonClickEventTriggerBehaviorView"
             xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:i="using:Avalonia.Xaml.Interactivity"
             xmlns:ia="using:Avalonia.Xaml.Interactions.Core"
             xmlns:ic="using:Avalonia.Xaml.Interactions.Custom"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450">
    <Grid RowDefinitions="*,Auto" ColumnDefinitions="30*,5,30*,5,30*">
        <Canvas Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5" Margin="5" Background="{DynamicResource GrayBrush}">
            <Ellipse Canvas.Left="{Binding Position, Mode=TwoWay}" Canvas.Top="200" Fill="{DynamicResource RedBrush}" Stroke="{DynamicResource YellowBrush}" StrokeThickness="5" Height="100" Width="100"/>
        </Canvas>
        <Button x:Name="MoveLeftButton" Content="Move Left (Hold Control)" Grid.Row="1" Grid.Column="0" Margin="5,0,0,5">
            <i:Interaction.Behaviors>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Control">
                    <ia:InvokeCommandAction Command="{Binding MoveLeftCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
            </i:Interaction.Behaviors>
        </Button>
        <Button x:Name="ResetMoveButton" Content="Reset Move (Hold Control+Shift)" Grid.Row="1" Grid.Column="2" Margin="0,0,0,5">
            <i:Interaction.Behaviors>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Control,Shift">
                    <ia:InvokeCommandAction Command="{Binding ResetMoveCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
            </i:Interaction.Behaviors>
        </Button>
        <Button x:Name="MoveRightButton" Content="Move Right (Hold Shift)" Grid.Row="1" Grid.Column="4" Margin="0,0,5,5">
            <i:Interaction.Behaviors>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Shift">
                    <ia:InvokeCommandAction Command="{Binding MoveRightCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
            </i:Interaction.Behaviors>
        </Button>
    </Grid>
</UserControl>

You can combine multiple triggers under one button behaviors collection:

        <Button Content="Left (Control), Reset (Hold Control+Shift), Right (Hold Shift)" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" Margin="5,0,0,5">
            <i:Interaction.Behaviors>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Control">
                    <ia:InvokeCommandAction Command="{Binding MoveLeftCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Shift">
                    <ia:InvokeCommandAction Command="{Binding ResetMoveCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
                <ic:ButtonClickEventTriggerBehavior KeyModifiers="Control,Shift">
                    <ia:InvokeCommandAction Command="{Binding MoveRightCommand}"/>
                </ic:ButtonClickEventTriggerBehavior>
            </i:Interaction.Behaviors>
        </Button>

@derekantrican
Copy link
Author

Excellent - those code samples helped me get up and running!

Just to let you know, using the xmlns:i="using:Avalonia.Xaml.Interactivity" gave me the error "Unable to resolve type Interaction from namespace using:Avalonia.Xaml.Interactivity" but changing it to xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity" seemed to work

@wieslawsoltes
Copy link
Contributor

Excellent - those code samples helped me get up and running!

Just to let you know, using the xmlns:i="using:Avalonia.Xaml.Interactivity" gave me the error "Unable to resolve type Interaction from namespace using:Avalonia.Xaml.Interactivity" but changing it to xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity" seemed to work

That sometime happens in previewer when assembly is not loaded so your solution is correct.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants