4

I have keyboard shortcuts declared in my xaml using KeyBindings. I would like to ignore repetitions due to key holding in few of them.

I have found only solutions using events and checking "IsRepetition", which doesnt really fit in my declaration of the keybindings.

Of course I could do it in the Command definition itself and measure a time difference between 2 last executes, but this gives me no way to differentiate multiple presses and 1 key holding.

What would be the best way to execute only on the first press and ignore the rest if the key is hold?

Tomas Grosup
  • 6,396
  • 3
  • 30
  • 44

3 Answers3

2

You are trying to change a behavior of the button. Better to use code for that. The easiest way is to attach a preview event to the window like that:

<Window 
       ...
          PreviewKeyDown="HandlePreviewKeyDown">

Then in code handle it like that:

    private void HandlePreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.IsRepeat)
        {
            e.Handled = true;
        }
    }

Sadly this would disable any repeat behavior, even in a textbox hosted by the form. This is an interesting question. If I find a more elegant way of doing this, I will add to the answer.

EDIT:

OK there are two ways to define Key Binding.

    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">


    <Window.InputBindings>
        <KeyBinding x:Name="altD" Gesture="Alt+D" Command="{Binding ClickCommand}"/>
    </Window.InputBindings>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
            <Button Content="_Click" Command="{Binding ClickCommand}" />
        <TextBox Grid.Row="1"/>
    </Grid>
</Window>

The above button will generate a click because you implicitely requested the Alt-C gesture via the underscore: _Click content. Then the window has an explicit keybinding to Alt+D.

This code behind should now work for both cases and should not interfere with regular repeat:

protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        base.OnPreviewKeyDown(e);

        if (e.IsRepeat)
        {
            if (((KeyGesture)altD.Gesture).Matches(this, e))
            {
                e.Handled = true;
            }
            else if (e.Key == Key.System)
            {
                string sysKey = e.SystemKey.ToString();
                //We only care about a single character here: _{character}
                if (sysKey.Length == 1 && AccessKeyManager.IsKeyRegistered(null, sysKey))
                {
                    e.Handled = true;
                }
            }
        }
    }
user195275
  • 1,039
  • 13
  • 18
0

I would say if you create a very simple state machine of sorts that would take action on the KeyBinding on a KeyDown event and would ignore all other input until a KeyUp event is fired to give the KeyBinding a "one-shot" behavior.

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keyup.aspx

cowboydan
  • 1,062
  • 7
  • 15
0

Use the keyUp method instead of KeyDown.