WPF MVVM KeyBinding不能立即识别并且不总是起作用。

5

不知为何,我的UserControl的KeyBindings在WPF应用程序加载后就不起作用了。只有在我按下表单上的按钮后才能起作用,但是当我通过点击、alt+tab或移动等方式将焦点设置到表单时却无法起作用。而且当它们起作用时,我的回车键会打印一个随机数字(有时是5,有时是7等等...)。

<UserControl x:Class="WpfCalculator.View.CalculatorView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300"
    >
<UserControl.InputBindings>
    <KeyBinding Key="DELETE" Command="{Binding Path=IBackspaceOnInput}" />
    <KeyBinding Key="BACKSPACE" Command="{Binding Path=IBackspaceOnInput}" />

    <KeyBinding Key="NUMPAD0" Command="{Binding Path=IAppendToUserInput}" CommandParameter="0" />
    <KeyBinding Key="NUMPAD1" Command="{Binding Path=IAppendToUserInput}" CommandParameter="1" />
    <KeyBinding Key="NUMPAD2" Command="{Binding Path=IAppendToUserInput}" CommandParameter="2" />
    <KeyBinding Key="NUMPAD3" Command="{Binding Path=IAppendToUserInput}" CommandParameter="3" />
    <KeyBinding Key="NUMPAD4" Command="{Binding Path=IAppendToUserInput}" CommandParameter="4" />
    <KeyBinding Key="NUMPAD5" Command="{Binding Path=IAppendToUserInput}" CommandParameter="5" />
    <KeyBinding Key="NUMPAD6" Command="{Binding Path=IAppendToUserInput}" CommandParameter="6" />
    <KeyBinding Key="NUMPAD7" Command="{Binding Path=IAppendToUserInput}" CommandParameter="7" />
    <KeyBinding Key="NUMPAD8" Command="{Binding Path=IAppendToUserInput}" CommandParameter="8" />
    <KeyBinding Key="NUMPAD9" Command="{Binding Path=IAppendToUserInput}" CommandParameter="9" />

    <KeyBinding Key="D0" Command="{Binding Path=IAppendToUserInput}" CommandParameter="0" />
    <KeyBinding Key="D1" Command="{Binding Path=IAppendToUserInput}" CommandParameter="1" />
    <KeyBinding Key="D2" Command="{Binding Path=IAppendToUserInput}" CommandParameter="2" />
    <KeyBinding Key="D3" Command="{Binding Path=IAppendToUserInput}" CommandParameter="3" />
    <KeyBinding Key="D4" Command="{Binding Path=IAppendToUserInput}" CommandParameter="4" />
    <KeyBinding Key="D5" Command="{Binding Path=IAppendToUserInput}" CommandParameter="5" />
    <KeyBinding Key="D6" Command="{Binding Path=IAppendToUserInput}" CommandParameter="6" />
    <KeyBinding Key="D7" Command="{Binding Path=IAppendToUserInput}" CommandParameter="7" />
    <KeyBinding Key="D8" Command="{Binding Path=IAppendToUserInput}" CommandParameter="8" />
    <KeyBinding Key="D9" Command="{Binding Path=IAppendToUserInput}" CommandParameter="9" />

    <KeyBinding Key="ADD" Command="{Binding Path=IAppendToUserInput}" CommandParameter="+" />
    <KeyBinding Key="SUBTRACT" Command="{Binding Path=IAppendToUserInput}" CommandParameter="-" />
    <KeyBinding Key="MULTIPLY" Command="{Binding Path=IAppendToUserInput}" CommandParameter="*" />
    <KeyBinding Key="DIVIDE" Command="{Binding Path=IAppendToUserInput}" CommandParameter="/" />

    <KeyBinding Key="Return" Command="{Binding Path=ICalculateExpression}" CommandParameter="" />
    <KeyBinding Key="Enter" Command="{Binding Path=ICalculateExpression}" CommandParameter="" />
    <KeyBinding Key="Escape" Command="{Binding Path=IClearInput}" CommandParameter="" />

    <KeyBinding Gesture="CTRL+M" Command="{Binding Path=IRememberExpression}" CommandParameter="" />
    <KeyBinding Gesture="CTRL+R" Command="{Binding Path=IRecallExpression}" CommandParameter="" />
    <KeyBinding Gesture="CTRL+X" Command="{Binding Path=IForgetExpression}" CommandParameter="" />

    <KeyBinding Key="Left" Command="{Binding Path=IMMoveCursor}" CommandParameter="1" />
    <KeyBinding Key="Right" Command="{Binding Path=IMMoveCursor}" CommandParameter="-1" />

</UserControl.InputBindings>

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="305" Width="489">
    <TextBox Name="input" HorizontalAlignment="Right"  IsReadOnly="True" Margin="0,12,200,271" Text="{Binding Path=UserInput}" Width="275" />
    <Button Content="CE" Margin="143,0,323,147" Command="{Binding Path=IBackspaceOnInput}" CommandParameter="" Height="23" VerticalAlignment="Bottom" />
    <Button Content="1" Height="23" HorizontalAlignment="Right" Margin="0,106,294,176" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="1" />
    <Button Content="2" Height="23" HorizontalAlignment="Right" Margin="0,106,265,176" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="2" />
    <Button Content="3" Height="23" HorizontalAlignment="Right" Margin="0,106,236,176" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="3" />
    <Button Content="4" Height="23" HorizontalAlignment="Right" Margin="0,77,294,205" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="4" />
    <Button Content="5" Height="23" HorizontalAlignment="Right" Margin="0,77,236,205" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="5" />
    <Button Content="6" Height="23" HorizontalAlignment="Right" Margin="0,77,265,205" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="6" />
    <Button Content="7" Height="23" HorizontalAlignment="Right" Margin="0,48,294,234" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="7" />
    <Button Content="8" Height="23" HorizontalAlignment="Right" Margin="0,48,265,234" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="8" />
    <Button Content="9" Height="23" HorizontalAlignment="Right" Margin="0,48,236,234" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="9" />
    <Button Content="0" Height="23" HorizontalAlignment="Left" Margin="201,135,0,147" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="0" />

    <Button Content="+" Height="23" HorizontalAlignment="Right" Margin="0,48,201,234" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="+" />
    <Button Content="-" Height="23" HorizontalAlignment="Right" Margin="0,77,201,205" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="-" />
    <Button Content="*" Height="23" HorizontalAlignment="Right" Margin="0,106,201,176" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="*" />
    <Button Content="/" Height="23" HorizontalAlignment="Right" Margin="0,135,201,147" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="/" />
    <Button Content="." Height="23" HorizontalAlignment="Right" Margin="0,135,236,147" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="9" />

    <Button Content="C" HorizontalAlignment="Right" Margin="0,164,323,118" Width="23" Command="{Binding Path=IClearInput}" CommandParameter="" />
    <Button Content="MC" Height="23" HorizontalAlignment="Right" Margin="0,0,323,234" VerticalAlignment="Bottom" Width="23" Command="{Binding Path=IForgetExpression}" CommandParameter=""/>
    <Button Content="M+" Height="23" HorizontalAlignment="Right" Margin="0,0,323,176" VerticalAlignment="Bottom" Width="23" Command="{Binding Path=IRememberExpression}" CommandParameter=""/>
    <Button Content="MR" Height="23" HorizontalAlignment="Right" Margin="0,0,323,205" VerticalAlignment="Bottom" Width="23" Command="{Binding Path=IRecallExpression}" CommandParameter=""/>

    <Expander ExpandDirection="Left" Header="History" Height="91" HorizontalAlignment="Right" Margin="0,193,200,0" VerticalAlignment="Top" Width="275">
        <ListView ItemsSource="{Binding Path=History}" >
            <ListView.View>
                <GridView >
                    <GridViewColumn Header="Start" DisplayMemberBinding="{Binding Started}"/>
                    <GridViewColumn Header="End" DisplayMemberBinding="{Binding Completed}"/>
                    <GridViewColumn Header="Expression" DisplayMemberBinding="{Binding Calculation}"/>
                    <GridViewColumn Header="Solution" DisplayMemberBinding="{Binding Result}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Expander>
    <Button Command="{Binding Path=ICalculateExpression}" CommandParameter="" IsEnabled="{Binding Path=IsEqualsBtnEnabled}" Content="=" Height="23" Margin="172,0,236,118" VerticalAlignment="Bottom" />

</Grid></UserControl>

我真的没有遇到过其他人有这个特定的问题,所以我不太确定该给出什么更多的信息。如果需要其他信息,请告诉我。

3个回答

6

您是否使用Mole验证控件在加载时实际上具有焦点?可能是因为您的父控件保持焦点,直到手动选择按钮。至于回车键,则听起来好像它们可能会选择最后单击的按钮,因为它仍然具有焦点而不是触发您的命令。

您可能需要查看您的命令,因为我不确定声明是否设置正确。对于KeyBinding,您的命令应该在XAML中引用为CommandReference,就像this article所描述的那样。


我将尝试按照您的建议使用CommandReference来绑定输入。我目前使用的是Visual Studio 2010,所以我还没有尝试过Mole。(您是否知道其他检查方法?)但是我对文章中提供的一些信息感到有些困惑。根据文章,我应该会收到一个异常,但是目前我的应用程序运行良好,除了我目前正在处理的问题。 - Terrance
你的回答确实帮助了我,至少在按钮点击行为方面。但是,我还需要使用FocusManager.FocusedElement="{Binding ElementName=input}"来设置文本框的焦点。虽然我肯定会记住将非依赖属性附加到控件时使用命令引用,但它对应用程序没有产生任何影响。没有愚蠢的绑定双关语哈哈。 - Terrance
一个ClickMode的例子:我之前提到过 <Button Content="1" Height="23" HorizontalAlignment="Right" Margin="0,106,294,176" Width="23" Command="{Binding Path=IAppendToUserInput}" CommandParameter="1" ClickMode="Press" /> - Terrance
1
很高兴知道命令参考没有起到作用,但无论如何,很高兴这个帮助了。我以前没有遇到过这种特殊情况,所以我会记下来,以便将来使用。 - Jeff Wain

1

我遇到了同样的问题。我对焦点问题进行了跟进。我发现当我将焦点设置为表单内的按钮时,命令开始起作用。如果我的焦点项目被删除而没有重定向(例如从列表框中删除最后一个项目),那么我的所有命令都无法工作。

在导致我的命令中断的奇怪状态下,我手动将键盘焦点重置为默认项目。在我的情况下,这是页面加载事件和删除命令(当我的列表框中没有更多项目时)。


1
我不确定这是否完全回答了你的问题,但是大多数我的按键绑定/焦点问题都可以通过将Focusable设置为True在你的用户控件上解决,然后在代码后端,在视图加载事件中调用Focus()来解决。
    <UserControl ....
         Focusable="True"
         Loaded="Act_Loaded" >

    private void Act_Loaded(object sender, RoutedEventArgs e)
    {
        Focus();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接