简体   繁体   中英

Do not trigger click on focused element when hitting ctrl+space

In my WPF application a "global" search box appears when hitting Ctrl+Space. It behaves like Spotlight in Mac OS when hitting Command+Space.

MainWindow.xaml.cs

public partial class MainWindow : Window
{
  public static RoutedCommand OpenSpotlight { get; set; } = new RoutedCommand();

  public MainWindow()
  {
    OpenSpotlight.InputGestures.Add(new KeyGesture(Key.Space, ModifierKeys.Control));
  }

  private void OpenSpotlight_Execute(object sender, ExecutedRoutedEventArgs e)
  {
    // Code which opens the search box ...
  }
}

MainWindow.xaml

<Window.CommandBindings>
  <CommandBinding Command="{x:Static local:MainWindow.OpenSpotlight}" Executed="OpenSpotlight_Execute"/>
</Window.CommandBindings>

Works fine, except one problem: when any button is focused, hitting Ctrl+Space triggers the button to be clicked because Space key is being hit.

Is there any way to omit this behaviour? I think of changing/removing the focus globally when Ctrl key is hit but don't know how this can be implemented ...

Instead of using a RoutedCommand and a CommandBinding , you could just handle the PreviewKeyDown event:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        PreviewKeyDown += OnPreviewKeyDown;
    }

    private void OnPreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space
            && (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
        {
            e.Handled = true;
            // Code which opens the search box ...
        }
    }
}

This solution doesn't require you to add anything to the XAML markup.

I haven't tried this, but seems quite logical to me.

You can handle the KeyDown and/or PreviewKeyDown event of a button and skip the Space press. Something like this could work :

private void GlobalButton_PreviewKeyDown(object sender, KeyEventArgs e)
{
 if (e.Key == Key.Space)
 e.Handled = true;
}

Wondering how you'ld do this for all the buttons? Here's a function to find a control of a given type:

public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : 
DependencyObject
{
if (depObj != null)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
        if (child != null && child is T)
        {
            yield return (T)child;
        }

        foreach (T childOfChild in FindVisualChildren<T>(child))
        {
            yield return childOfChild;
        }
    }
}
}

Simply loop through the buttons on window_load or similar events:

foreach (Button btn in FindVisualChildren<Button>(this))
{
  btn.KeyDown += GlobalButton_PreviewKeyDown;
  btn.PreviewKeyDown += GlobalButton_PreviewKeyDown;
}

Hopefully this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM