简体   繁体   English

是否可以将按键绑定到按钮的 Click 事件?

[英]Is it possible to bind a key to the Click event of a button?

I am building a calculator App on WPF and I would like to bind the NumPad Keys to their respective buttons since up until now the only way of using the App is by clicking with the mouse on every button and it is not ideal.我正在 WPF 上构建一个计算器应用程序,我想将 NumPad 键绑定到它们各自的按钮,因为到目前为止,使用该应用程序的唯一方法是在每个按钮上单击鼠标,这并不理想。

This is the first time working with WPF so I've been searching for an answer but couldn't find anything useful.这是第一次使用 WPF 所以我一直在寻找答案但找不到任何有用的东西。

I did try adding this to my code but it does nothing when I press "A".我确实尝试将它添加到我的代码中,但是当我按“A”时它什么也没做。 It also doesn't work if I add a modifier like "Shift".如果我添加像“Shift”这样的修饰符,它也不起作用。

<Window ...>
    <Window.InputBindings>
        <KeyBinding Key="A" Command="{Binding Button_Click}"/>
    </Window.InputBindings>
    ...
</Window>

That's not quite how commands work.不是命令的工作方式。 If you want to use commands to execute custom behavior I highly recommend you install the CommunityToolkit.Mvvm NuGet package, which will grant you access to RelayCommand .如果您想使用命令来执行自定义行为,我强烈建议您安装CommunityToolkit.Mvvm NuGet package,这将授予您访问RelayCommand的权限。

Typically, with MVVM, ViewModels are set as the DataContext for views, but you don't have to do all that if you just want to use commands to bind to code behind behavior.通常,对于 MVVM,ViewModel 被设置为视图的 DataContext,但如果您只想使用命令绑定到代码隐藏行为,则不必执行所有这些操作。

In your Window code-behind, add a property of type RelayCommand and initializing it in your constructor binding it to a function like so:在您的 Window 代码隐藏中,添加 RelayCommand 类型的属性并在构造函数中初始化它,将其绑定到 function,如下所示:

public partial class MainWindow : Window
{
    public RelayCommand ClickCommand { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        ClickCommand = new RelayCommand(ButtonClickAction);
    }

    private void ButtonClickAction()
    {
        MessageBox.Show("The Button was clicked!");
    }
}

Then in your XAML, you can bind to that command as long as the DataContext you're binding to is the Window class.然后在您的 XAML 中,您可以绑定到该命令,只要您绑定到的 DataContext 是Window class。

Here's an example with both the Button AND the KeyBinding bound to the same behavior:这是一个 Button 和 KeyBinding 绑定到相同行为的示例:

<Window ...>
    <Window.InputBindings>
        <KeyBinding Key="A" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ClickCommand}" />
    </Window.InputBindings>
    <Grid>
        <Button Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=ClickCommand}"
                Content="Click Me (A)" Width="100" Height="50"/>
    </Grid>
</Window>

Note the RelativeSource is directing the binding that the location of the ClickCommand RelayCommand should be found in an ancestor of type Window since it's the Window's where we defined the command.请注意, RelativeSource指示绑定,即ClickCommand RelayCommand 的位置应该在类型为Window的祖先中找到,因为它是我们定义命令的窗口。

Despite the solution already given, I would like to propose another implementation that does not depend on the Code Behind of the Window.尽管已经给出了解决方案,但我想提出另一个不依赖于 Window 的代码隐藏的实现。

using Simplified;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Markup;

namespace Helpers
{
    /// <summary>Static class with various helper members</summary>
    public static partial class WinHelper
    {
        public static RelayCommand RaiseClickCommand = new RelayCommand(
            obj =>
            {
                switch (obj)
                {
                    case FrameworkElement element:
                        RoutedEvent? clickEvent = element switch
                        {
                            ButtonBase => ButtonBase.ClickEvent,
                            MenuItem => MenuItem.ClickEvent,
                            _ => null
                        };
                        if (clickEvent is not null)
                        {
                            element.RaiseEvent(new RoutedEventArgs(clickEvent));
                        }
                        break;
                    case Hyperlink link:
                        link.RaiseEvent(new RoutedEventArgs(Hyperlink.ClickEvent));
                        break;
                    default: break;
                }
            },
            obj => obj is ButtonBase or MenuItem or Hyperlink
        );
    }

    /// <summary>For ease of use in XAML</summary>
    [MarkupExtensionReturnType(typeof(RelayCommand))]
    public class RaiseClickExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return WinHelper.RaiseClickCommand;
        }
    }
}

An example of its use:其使用示例:

    <Window.InputBindings>
        <KeyBinding Key="A" Command="{helpers:RaiseClick}" CommandParameter="{Binding ElementName=btnA}"/>
        <KeyBinding Key="B" Command="{helpers:RaiseClick}" CommandParameter="{Binding ElementName=btnB}"/>
    </Window.InputBindings>
    <UniformGrid >
        <Button x:Name="btnA" Content="Clik Me #A" Click="OnClickMeA"/>
        <Button x:Name="btnB" Content="Clik Me #B" Click="OnClickMeB"/>
        <x:Code>
            <![CDATA[
        private void OnClickMeA(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Click A");
        }
        private void OnClickMeB(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Click B");
        }
            ]]>
        </x:Code>
    </UniformGrid>

This solution can be used for buttons of any type (Button, CheckBox, etc.), MenuItem and Hyperlink.此解决方案可用于任何类型的按钮(Button、CheckBox 等)、MenuItem 和 Hyperlink。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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