WPF KeyBinding禁用,让键盘快捷键冒泡

时间:2019-03-14 12:01:27

标签: wpf xaml mvvm icommand

我正在开发一个使用MVVM,KeyBinding和ICommand的项目。

我在同一窗口上有多个嵌套视图(UserControls),其中许多使用相同的键绑定“ Ctrl + S”来运行SaveCommand

与视图关联的ViewModel具有IsSaveCommandAvailable属性,该属性可以判断该视图模型中是否有SaveCommand

在我的情况下,只有“根”视图才能通过按Ctrl + S来启动SaveCommand,嵌套的视图必须忽略按键并让其冒泡到根视图,完成所有保存工作。

我搜寻了一个解决方案,但发现我可以使用ICommand.CanExecute返回false并避免运行KeyBinding。

但是此解决方案不符合我的需要,因为如果我在子视图上按Ctrl + S,则其SaveCommand CanExecute返回false,并且击键丢失。

有没有办法使按键击中气泡,直到可以运行KeyBinding?

2 个答案:

答案 0 :(得分:1)

我找到的解决方案是在KeyBinding的IValueConverter属性上使用Key,将布尔值转换为作为CommandParameter传递的键,如果值是false,返回Key.None

public class BooleanToKeyConverter : IValueConverter
{

    /// <summary>
    /// Key to use when the value is false
    /// </summary>
    public Key FalseKey { get; set; } = Key.None;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is bool flag && flag && parameter != null && parameter != DependencyProperty.UnsetValue)
        {
            if (parameter is Key key)
            {
                return key;
            }
            else if (Enum.TryParse<Key>(parameter.ToString(), out var parsedKey))
            {
                return parsedKey;
            }
        }
        return this.FalseKey;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

}

在资源文件中(例如:App.xaml):

<conv:BooleanToKeyConverter x:Key="boolToKey"/>

其中“ conv”是您的本地名称空间。

然后,在键绑定中:

<KeyBinding Command="{Binding Path=SaveCommand}" 
    Key="{Binding Path=IsSaveCommandAvailable, Converter={StaticResource boolToKey}, ConverterParameter=S}" 
    Modifiers="Ctrl"/>

答案 1 :(得分:1)

如果您希望保留Key属性不变(且可绑定),则可以派生KeyBinding并添加IsEnabled依赖属性,同时覆盖Gesture

public override InputGesture Gesture
{
    get
    {
        return IsEnabled ? base.Gesture as KeyGesture : new KeyGesture(Key.None);
    }
    set
    {
        base.Gesture = value;
    }
}
// IsEnabled dependency property changed callback
private static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    (d as MyKeyBinding)?.WritePostscript(); // raise Gesture changed
}

不要忘记通知UI Gesture中的IsEnabled已使用WritePostscript()更改了回调并覆盖了CreateInstanceCore
用法示例:

<utils:MyKeyBinding 
    Command="{Binding SaveCommand}" 
    Key="{Binding KeyBindings.SaveKey}" 
    Modifiers="{Binding KeyBindings.SaveModifiers}" 
    IsEnabled="{Binding IsSaveCommandAvailable}"/>