WPF'de klavye kısayolları


129

Bunun _yerine kullanmayı biliyorum &ama tüm Ctrl+ türü kısayollara bakıyorum .

Ctrl+ Zgeri almak için, Ctrl+ Skaydetmek için +

Bunları WPF uygulamalarında uygulamanın 'standart' bir yolu var mı? Yoksa kendi başınıza yuvarlayıp bunları hangi komuta / kontrole bağlarsınız?

Yanıtlar:


170

Bunun bir yolu, kısayol tuşlarınızı komutlara kendileri olarak eklemektir InputGestures. Komutlar olarak uygulanır RoutedCommands.

Bu, kısayol tuşlarının herhangi bir kontrole bağlı olmasalar bile çalışmasını sağlar. Menü öğeleri klavye hareketlerini anladığından, bu komutu menü öğenize bağlarsanız, menü öğeleri metninde kısayol tuşunu otomatik olarak görüntülerler.

  1. Bir komutu tutmak için statik öznitelik oluşturun (tercihen komutlar için oluşturduğunuz statik bir sınıfta bir özellik olarak - ancak basit bir örnek için, yalnızca window.cs'de statik bir öznitelik kullanarak):

     public static RoutedCommand MyCommand = new RoutedCommand();
  2. Yöntemi çağırması gereken kısayol tuşlarını ekleyin:

     MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
  3. Çalıştırmak için yönteminize işaret eden bir komut bağlama oluşturun. Bunları altında çalışması gereken UI öğesi (örneğin, pencere) ve yöntem için komut bağlamalarına yerleştirin:

     <Window.CommandBindings>
         <CommandBinding Command="{x:Static local:MyWindow.MyCommand}" Executed="MyCommandExecuted"/>
     </Window.CommandBindings>
    
     private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e) { ... }
    

4
Komutu bir menü öğesiyle nasıl ilişkilendiririm? Elbette bu cevaba dahil edilecek en önemli bilgi bu olurdu, ancak eksik.
Timwi

8
@Timwi: Mevcut bir olaya klavye kısayolu eklemek için yukarıdaki kodu bu şekilde kullandım: RoutedCommand cmndSettings = new RoutedCommand (); cmndSettings.InputGestures.Add (yeni KeyGesture (Key.S, ModifierKeys.Control)); CommandBindings.Add (yeni CommandBinding (cmndSettings, mnuSettings_Click));
itsho

1
itsho'nun yorumu bu işi benim için yaptı, yukarıdaki xml kodunu çalıştıramadı.
gosr

1
Ne yazık ki, bu yaklaşımla, Executedkomutun kodu, normal bir komutun (özel ICommanduygulama) kullanılmasının aksine, görünüm modelinden ziyade arka kodda (pencerenin veya kullanıcı kontrolünün) sonlanacaktır .
OR Mapper


98

Bunu tam olarak WPF'deki anahtar bağlama ile ilgili aradığım şey olarak buldum:

<Window.InputBindings>
        <KeyBinding Modifiers="Control"
                    Key="N"
                    Command="{Binding CreateCustomerCommand}" />
</Window.InputBindings>

MVVM CommandReference ve KeyBinding blog gönderisine bakın


Çok güzel ve kolay!
birleşme

1
"CreateCustomerCommand" ın ne olduğunu ve nasıl uygulanacağını açıklar mısınız?
Vinz

Kopyala ve yapıştırılan kod pasajı bağlantılı blog gönderisinde "Sonuç bir İstisna olacaktır" ile açıklandığı için bu hala yalnızca bir bağlantı yanıtıdır. : P
Martin Schneider

İşler burada harikadır. İlk olarak OP gibi düğme içeriğinin anahtarından önce "_" eklemeyi denedim, ancak işe yaramadı. En kötüsü, arayüzün yazılabilir bir nesnesine odaklanmadığımda tuşun kendisine bastığımda etkinleşti .. ctrl-s yerine kaydetmek için "s" gibi.
Jay

14

Bu kodu deneyin ...

Önce bir RoutedComand nesnesi oluşturun

  RoutedCommand newCmd = new RoutedCommand();
  newCmd.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control));
  CommandBindings.Add(new CommandBinding(newCmd, btnNew_Click));

9

Bunları nerede kullanmak istediğinize bağlı.

TextBoxBasetüretilmiş kontroller bu kısayolları zaten uyguluyor. Özel klavye kısayollarını kullanmak istiyorsanız, Komutlar ve Giriş hareketlerine bir göz atmalısınız. İşte Kodu Değiştir'den küçük bir öğretici : WPF Eğitimi - Komut Bağlamaları ve Özel Komutlar


8
Ne saçma bir öğretici - kesinlikle en önemli şeyi açıklamıyor, bu da önceden tanımlanmış 20 “ortak” komuttan biri olmayan bir komutun nasıl kullanılacağıdır.
Timwi

6

Bu yanıtı başkaları için belgelemek, bunu yapmanın çok daha basit bir yolu olduğu için nadiren başvurulur ve XAML'e dokunmayı hiç gerektirmez.

Bir klavye kısayolunu bağlamak için, Pencere yapıcısında InputBindings koleksiyonuna yeni bir KeyBinding eklemeniz yeterlidir. Komut olarak, ICommand uygulayan rasgele komut sınıfınızı iletin. Yürütme yöntemi için, ihtiyacınız olan mantığı uygulamanız yeterlidir. Aşağıdaki örneğimde, WindowCommand sınıfım her çağrıldığında çalıştıracağı bir temsilci alır. Yeni WindowCommand'i bağlamamla iletmek için oluşturduğumda, başlatıcımda, WindowCommand'in yürütmesini istediğim yöntemi belirtiyorum.

Kendi hızlı klavye kısayollarınızı bulmak için bu kalıbı kullanabilirsiniz.

public YourWindow() //inside any WPF Window constructor
{
   ...
   //add this one statement to bind a new keyboard command shortcut
   InputBindings.Add(new KeyBinding( //add a new key-binding, and pass in your command object instance which contains the Execute method which WPF will execute
      new WindowCommand(this)
      {
         ExecuteDelegate = TogglePause //REPLACE TogglePause with your method delegate
      }, new KeyGesture(Key.P, ModifierKeys.Control)));
   ...
}

Üzerinde herhangi bir yöntem kümesini ateşlemek için bir yürütme temsilcisini alan basit bir WindowCommand sınıfı oluşturun.

public class WindowCommand : ICommand
{
    private MainWindow _window;

    //Set this delegate when you initialize a new object. This is the method the command will execute. You can also change this delegate type if you need to.
    public Action ExecuteDelegate { get; set; }

    //You don't have to add a parameter that takes a constructor. I've just added one in case I need access to the window directly.
    public WindowCommand(MainWindow window)
    {
        _window = window;
    }

    //always called before executing the command, mine just always returns true
    public bool CanExecute(object parameter)
    {
        return true; //mine always returns true, yours can use a new CanExecute delegate, or add custom logic to this method instead.
    }

    public event EventHandler CanExecuteChanged; //i'm not using this, but it's required by the interface

    //the important method that executes the actual command logic
    public void Execute(object parameter)
    {
        if (ExecuteDelegate != null)
        {
            ExecuteDelegate();
        }
        else
        {
            throw new InvalidOperationException();
        }
    }
}

5

Benzer bir sorunla karşılaştım ve @ aliwa'nın yanıtını en yararlı ve en zarif çözüm olarak buldum; ancak belirli bir tuş kombinasyonuna ihtiyacım vardı, Ctrl+ 1. Maalesef şu hatayı aldım:

'1', 'Anahtar' için bir değer olarak kullanılamaz. Sayılar, geçerli numaralandırma değerleri değildir.

Biraz daha araştırarak, @ aliwa'nın aşağıdaki cevabını değiştirdim:

<Window.InputBindings>
    <KeyBinding Gesture="Ctrl+1" Command="{Binding MyCommand}"/>
</Window.InputBindings>

Bunu, ihtiyacım olan herhangi bir kombinasyon için oldukça iyi çalıştığını buldum.


Bu benim için çalıştı<UserControl.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding someCommand}"/> </UserControl.InputBindings>
fs_tigre

3

VB.NET:

Public Shared SaveCommand_AltS As New RoutedCommand

İçinde yüklü olay:

SaveCommand_AltS.InputGestures.Add(New KeyGesture(Key.S, ModifierKeys.Control))

Me.CommandBindings.Add(New CommandBinding(SaveCommand_AltS, AddressOf Me.save))

XAML gerekli değildir.


1

En iyi cevaplar doğru olsa da UIElement, özellikle Windowodaklanılması gereken unsurun farkında olmadığında , çözümün herhangi birine uygulanmasını sağlamak için ekli özelliklerle çalışmayı kişisel olarak seviyorum . Deneyimlerime göre, pencerenin genellikle kök kapsayıcıdan başka bir şey olmadığı birkaç görünüm modelinin ve kullanıcı kontrolünün bir bileşimini sıklıkla görüyorum.

Pasaj

public sealed class AttachedProperties
{
    // Define the key gesture type converter
    [System.ComponentModel.TypeConverter(typeof(System.Windows.Input.KeyGestureConverter))]
    public static KeyGesture GetFocusShortcut(DependencyObject dependencyObject)
    {
        return (KeyGesture)dependencyObject?.GetValue(FocusShortcutProperty);
    }

    public static void SetFocusShortcut(DependencyObject dependencyObject, KeyGesture value)
    {
        dependencyObject?.SetValue(FocusShortcutProperty, value);
    }

    /// <summary>
    /// Enables window-wide focus shortcut for an <see cref="UIElement"/>.
    /// </summary>
    // Using a DependencyProperty as the backing store for FocusShortcut.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusShortcutProperty =
        DependencyProperty.RegisterAttached("FocusShortcut", typeof(KeyGesture), typeof(AttachedProperties), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, new PropertyChangedCallback(OnFocusShortcutChanged)));

    private static void OnFocusShortcutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is UIElement element) || e.NewValue == e.OldValue)
            return;

        var window = FindParentWindow(d);
        if (window == null)
            return;

        var gesture = GetFocusShortcut(d);
        if (gesture == null)
        {
            // Remove previous added input binding.
            for (int i = 0; i < window.InputBindings.Count; i++)
            {
                if (window.InputBindings[i].Gesture == e.OldValue && window.InputBindings[i].Command is FocusElementCommand)
                    window.InputBindings.RemoveAt(i--);
            }
        }
        else
        {
            // Add new input binding with the dedicated FocusElementCommand.
            // see: https://gist.github.com/shuebner20/349d044ed5236a7f2568cb17f3ed713d
            var command = new FocusElementCommand(element);
            window.InputBindings.Add(new InputBinding(command, gesture));
        }
    }
}

Bu ekli özellik ile herhangi bir UIElement için bir odak kısayolu tanımlayabilirsiniz. Öğeyi içeren pencerede girdi bağlamasını otomatik olarak kaydedecektir.

Kullanım (XAML)

<TextBox x:Name="SearchTextBox"
         Text={Binding Path=SearchText}
         local:AttachedProperties.FocusShortcutKey="Ctrl+Q"/>

Kaynak kodu

FocusElementCommand uygulamasını içeren tam örnek özet olarak mevcuttur: https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d

Sorumluluk Reddi: Bu kodu her yerde ve ücretsiz olarak kullanabilirsiniz. Lütfen bunun yoğun kullanıma uygun olmayan bir numune olduğunu unutmayınız. Örneğin, Komut, öğeye güçlü bir referans tutacağından, kaldırılan öğelerin çöp toplama işlemi yoktur.


-2

Komut a ile nasıl ilişkilendirilir MenuItem:

<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.