programing

WPF 키보드숏컷

megabox 2023. 4. 19. 22:54
반응형

WPF 키보드숏컷

i i i i 、 i 、 i 、 i 、 i 、 i 、 i i 。_&단, +타입 단축키는 모두 표시되어 있습니다.

Ctrl+Z 실행 취소,S + 저장 등

WPF 어플리케이션에서 이를 구현하기 위한 '표준' 방법이 있습니까?아니면 직접 롤링을 해서 어떤 명령/컨트롤에 연결시키는 경우입니까?

하나의 방법은 명령어에 단축키를 추가하는 것입니다.명령어는 로 구현됩니다.

이렇게 하면 컨트롤에 연결되어 있지 않아도 바로 가기 키가 작동할 수 있습니다.또한 메뉴 항목은 키보드 제스처를 인식하므로 해당 명령을 메뉴 항목에 연결하면 메뉴 항목 텍스트에 바로 가기 키가 자동으로 표시됩니다.


순서

  1. 명령어를 보유하는 static Atribute를 만듭니다(명령어용으로 작성하는 스태틱클래스의 속성으로 사용할 수도 있지만 간단한 예로서 window.cs의 static Atribute를 사용합니다).

     public static RoutedCommand MyCommand = new RoutedCommand();
    
  2. 메서드를 호출해야 하는 바로 가기 키를 추가합니다.

     MyCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));
    
  3. 실행 시 호출할 메서드를 가리키는 명령 바인딩을 만듭니다.작업하는 UI 요소(예: 창) 및 메서드의 명령 바인딩에 다음 명령을 입력합니다.

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

WPF의 키바인딩과 관련하여 찾고 있던 것이 바로 이것입니다.

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

블로그 게시 MVVM 명령 참조 및 키 바인딩을 참조하십시오.

이거 먹어봐.

먼저 RoutedCommand 개체를 만듭니다.

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

그건 어디에 쓰느냐에 따라 달라요.

TextBoxBase- 파생 컨트롤은 이미 이러한 바로 가기를 구현하고 있습니다.커스텀 키보드숏컷을 사용하는 경우는, 커맨드 및 입력 제스처를 참조해 주세요.코드: WPF 튜토리얼 - 명령어바인딩과 커스텀명령어관한 스위치의 작은 튜토리얼을 다음에 나타냅니다.

이 답변은 다른 사용자를 위해 문서화합니다.이는 거의 참조되지 않고 XAML을 조작할 필요가 없는 매우 간단한 방법이 있기 때문입니다.

키보드 단축키를 링크하려면 Window 컨스트럭터에서 새로운 KeyBinding을 InputBindings 컬렉션에 추가합니다.명령어로서 ICMand를 구현하는 임의의 명령어클래스를 전달합니다.실행 방법은 필요한 로직을 구현하기만 하면 됩니다.아래 예에서는 WindowCommand 클래스가 호출될 때마다 실행되는 위임자를 사용합니다.바인딩과 함께 전달될 새 WindowCommand를 구성할 때는 이니셜라이저에 WindowCommand를 실행할 메서드를 표시하기만 하면 됩니다.

이 패턴을 사용하여 빠른 단축키를 만들 수 있습니다.

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)));
   ...
}

간단한 WindowCommand 클래스를 만듭니다. 이 클래스는 실행 위임자가 설정된 메서드를 모두 실행합니다.

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();
        }
    }
}

비슷한 문제가 있어서 @aliwa의 답변이 가장 유용하고 우아한 솔루션이라는 것을 알게 되었습니다만, +라는 특정 키의 조합이 필요했습니다.불행하게도 다음과 같은 오류가 발생했습니다.

'1'은 'Key' 값으로 사용할 수 없습니다.숫자는 유효한 열거 값이 아닙니다.

조금 더 검색해서 @aliwa의 답변을 다음과 같이 수정했습니다.

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

필요한 조합이라면 어떤 조합에도 효과가 있다는 것을 알았습니다.

VB.NET:

Public Shared SaveCommand_AltS As New RoutedCommand

로드된 이벤트 내부:

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

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

XAML은 필요 없습니다.

, 을 사용하여 이 어떤 될 수 것을 .UIElement, 「」, 「」의 Window초점을 맞춰야 할 요소를 인식하지 못합니다.제 경험으로는 여러 뷰 모델과 사용자 컨트롤의 구성을 자주 볼 수 있는데, 이 경우 창은 루트 컨테이너와 다를 바 없습니다.

단편

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));
        }
    }
}

이 첨부 속성을 사용하여 모든 UIlement에 대한 포커스 바로 가기를 정의할 수 있습니다.요소를 포함하는 창에서 입력 바인딩을 자동으로 등록합니다.

사용방법(XAML)

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

소스 코드

FocusElementCommand 구현을 포함한 전체 샘플은 https://gist.github.com/shuebner20/c6a5191be23da549d5004ee56bcc352d에서 확인할 수 있습니다.

면책사항:이 코드는 어디서나 무료로 사용할 수 있습니다.이것은 대량 사용에 적합하지 않은 샘플이므로 주의해 주십시오.예를 들어 명령어는 요소에 대한 강력한 참조를 유지하므로 제거된 요소의 가비지 컬렉션은 없습니다.

XAML을 사용하여 여러 가지 방법을 시도해 봤지만 효과가 없었습니다.나는 마침내 샤히드 네르문다가 증명한 답을 바탕으로 해결책을 찾았다.

먼저 메뉴 모음:

<Menu x:Name="MainMenuBar" Grid.Row="0" HorizontalContentAlignment="Left">
    <MenuItem Header="_File" HorizontalContentAlignment="Left">
        <MenuItem x:Name="NewProjectMenuItem"
                    Header="New Project"
                    InputGestureText="Ctrl+N"
                    Click="NewProject_Click"/>
        <MenuItem x:Name="OpenProjectMenuItem"
                    Header="Open Project"
                    InputGestureText="Ctrl+O"
                    Click="OpenProject_Click"/>
        <MenuItem x:Name="CloseProjectMenuItem"
                    Header="Close Project"
                    Click="CloseProject_Click"/>
        <Separator/>
        <MenuItem x:Name="SaveProjectMenuItem"
                    Header="Save Project"
                    InputGestureText="Ctrl+S"
                    Click="SaveProject_Click"/>
        <MenuItem x:Name="SaveProjectAsMenuItem"
                    Header="Save Project As ..."
                    InputGestureText="Shift+Ctrl+S"
                    Click="SaveProjectAs_Click"/>
        <Separator/>
        <MenuItem x:Name="ExitMenuItem"
                    Header="Exit"
                    InputGestureText="Alt+F4"
                    Click="Exit_Click"/>
    </MenuItem>
</Menu>

화려하지 않다.각 메뉴 항목에는 'InputGesture'가 있습니다.텍스트 속성(닫기 제외)

그런 다음 Click=clicktab]" 명령에 의해 자동으로 생성된 클릭 이벤트 메서드를 수정했습니다.여기에서는 단축키가 정의되어 있는 경우와 정의되어 있지 않은 경우(닫기)의 2개만 표시하고 있습니다.

private void OpenProject_Executed(object sender, ExecutedRoutedEventArgs e) => OpenProject_Click(sender, e);
private void OpenProject_Click(object sender, RoutedEventArgs e)
{
    OpenProject();
}

private void CloseProject_Click(object sender, RoutedEventArgs e)
{
    CloseProject();
}

XXX_Executed(...) 메서드는 바로가기바인딩(다음으로 넘어가겠습니다)으로 호출되며 XXX_Click 메서드는 Click 명령으로 호출됩니다.

New Project, Open Project, Save Project As 및 Exit auto-generated XXX_Click 메서드에 대해서도 동일한 작업을 수행했습니다.

그런 다음 바인딩을 사용하여 새 파일을 만들었습니다(바인딩을 추가할 때 쉽게 찾을 수 있도록 분리했습니다).

partial class MainWindow
{
    private void BindShortcuts()
    {
        BindShortcut(Key.N, ModifierKeys.Control, NewProject_Executed);
        BindShortcut(Key.O, ModifierKeys.Control, OpenProject_Executed);
        BindShortcut(Key.S, ModifierKeys.Control, SaveProject_Executed);
        BindShortcut(Key.S, ModifierKeys.Control | ModifierKeys.Shift, SaveProjectAs_Executed);
        BindShortcut(Key.F4, ModifierKeys.Alt, Exit_Executed);
    }

    private void BindShortcut(Key key, ModifierKeys modifiers, ExecutedRoutedEventHandler executed)
    {
        RoutedCommand cmd = new();
        _ = cmd.InputGestures.Add(new KeyGesture(key, modifiers));
        _ = CommandBindings.Add(new CommandBinding(cmd, executed));
    }
}

이렇게 하면 더 많은 바로가기가 연결된 새로운 메뉴 항목을 추가할 때 적절한 <MenuItem .../> 태그를 추가하고 XXX_Executed 메서드를 정의하여 자동 생성된 XXX_Click 메서드를 호출하고 BindShorts() 함수를 갱신하기만 하면 됩니다.

마지막으로 Main Window 클래스의 컨스트럭터에 다음 항목을 추가했습니다.

public MainWindow()
{
    InitializeComponent();
    BindShortcuts();
}

마법처럼 작동한다.

특수한 경우: 포커스가 "원어민이 아닌" 요소에 있는 경우 바로 가기가 트리거되지 않습니다.예를 들어 WpfCurrencyTextbox에 초점을 맞추어도 XAML에 정의된 바로가기가 트리거되지 않습니다(oliwa의 답변과 동일).

NHotkey 패키지로 숏컷을 글로벌하게 만들어 이 문제를 해결했습니다.

즉, XAML의 경우 필요한 것은,

<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}" />

타고

<KeyBinding Gesture="Ctrl+Alt+Add" Command="{Binding IncrementCommand}"
            HotkeyManager.RegisterGlobalHotkey="True" />

WPF 및 사용하여 CTRL+SHIFT+(LETTER)를 발음하는 글로벌 단축키를 등록하는 방법에도 답변이 게재되어 있습니다.NET 3.5?

명령어를 에 관련짓는 방법MenuItem:

<MenuItem Header="My command" Command="{x:Static local:MyWindow.MyCommand}"/>

언급URL : https://stackoverflow.com/questions/1361350/keyboard-shortcuts-in-wpf

반응형