【问题标题】:WPF KeyBinding disable and let bubble up keyboard shortcutWPF KeyBinding 禁用并让键盘快捷键冒泡
【发布时间】:2019-03-14 12:01:26
【问题描述】:

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

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

与 View 关联的 ViewModel 有一个 IsSaveCommandAvailable 属性,可以判断 SaveCommand 在该 ViewModel 中是否可用。

在我的情况下,只有“根”视图必须能够通过按 Ctrl+S 来启动SaveCommand,嵌套的视图必须忽略按键并让它冒泡到根视图,确实如此所有保存的东西。

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

但是这个解决方案不符合我的需求,因为如果我在子视图上按 Ctrl+S,它的 SaveCommandCanExecute 返回 false,并且按键丢失。

有没有办法在 KeyBinding 可以运行之前使按键冒泡?

【问题讨论】:

    标签: wpf xaml mvvm icommand


    【解决方案1】:

    我找到的解决方案是在KeyBinding的Key属性上使用IValueConverter,将布尔值转换为作为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”是您的本地命名空间。

    然后,在 KeyBindings 中:

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

    【讨论】:

    • sooo 如果您已经收到回复,那么在这里发布这个有什么意义?寻找更好的方法?
    • @DenisSchaf,Stack Overflow 完全支持自我回答问题。我们存在是为了帮助他人。这个问题(和答案)现在有望帮助将来遇到同样问题的人。 stackoverflow.com/help/self-answer
    【解决方案2】:

    如果您希望保持 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}"/>
    

    【讨论】:

    • 我喜欢你的解决方案!它看起来比我的更具可读性和灵活性!
    猜你喜欢
    • 1970-01-01
    • 2012-11-06
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    相关资源
    最近更新 更多