我目前陷入一个无法找到答案的问题。它涉及“覆盖”'使用MVVM内置TextBox键盘功能。这是我的问题:
我有一个TextBox,用户在运行时输入文本。我正在寻找实现键盘快捷键,或使用此TextBox输入绑定。我开始使用似乎是标准的基于ICommand接口的方法,我简单地实现了:
<TextBox.InputBindings>
<KeyBinding Key="Up" Command="{Binding testCommand}" Modifiers="Ctrl" />
</TextBox.InputBindings>
我的想法是我执行与ViewModel中设置的ICommand属性相关联的命令。但是,TextBox类已经包含了CTRL + UP的烘焙函数,正如您所知,它将插入符号移动到TextBox输入字段的开头。除了我的Command之外,此函数还会执行,从而产生我想要的更改,但也会移动插入符号。
在MVVM之前,我只需在Code-Behind中使用PreviewKeyDown事件,检测所需的键组合并使用
e.Handled = true;
阻止TextBox触发其内置命令。然而,这不是最佳解决方案,因为它可能违反了MVVM原则。与XAML中声明的InputBinding一起实现也很困难。
在我的研究过程中,我发现了一个article,它描述了使用Blend提供的类,允许基于事件执行命令,可能允许我监听PreviewKeyDown事件,该事件在构建之前触发在函数中,但这意味着我不会在XAML中声明我的键绑定,因为语法似乎不支持keypress特定条件或InputBindings。我必须在ViewModel中执行所有键组合处理逻辑,这似乎是View应该做的事情。
进一步的研究使我进入了一个有趣的新领域,涉及拦截和替换某些“应用程序命令”。使用在CanExecute上始终返回false的Command,有效地删除了该函数。我找到了case,有人想要替换默认的CTRL + Z功能。完整问题的简略版本显示了基本概念:
textBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo,
UndoCommand, CanUndoCommand));
对这个ApplicationCommands类的研究使我得到了一些其他类,其中一个类更直接地与我的问题有关:ComponentCommands。 MSDN将该类描述为包含(除其他外)
ComponentCommands.MoveToHome
适合我的Ctrl + Up命令的内置功能。使用我先前链接的SO问题中的语法,理论上我可以阻止该命令执行,这是朝着正确方向迈出的一步。但是,我希望在ViewModel中通过ViewModel属性来定制触发我的Command的键组合,这些属性可以在XAML中绑定到InputBindings。如果我实现了这种方法,那就意味着我无法提前知道哪些内置函数可能与用户选择的键绑定冲突。
在我通过处理Code-Behind中的事件处理程序中的参数切换到MVVM之前,这自然得到了解决,如前所述。我写入PreviewKeyDown事件处理程序的任何键组合,我有一个特殊的操作,将e.Handled设置为true,有效地防止在事件处理程序完成后执行完该方法后可能出现的任何可能的内置命令。
我是否可以使用XAML中声明的InputBinding实现此功能?我有什么选择?
一些想法:
也许我可以在我的TextBox上公开PreviewKeyDown的事件处理程序,并在方法内部迭代所有TextBox的InputBindings,寻找与提供的按键匹配的提供的键组合,如果找到,我执行相关命令并将e.handled设置为true?我不熟悉从Code-Behind操作InputBindings,所以我不确定这将是多么实际,或者它是否会对应用程序施加太多负担(想象用户按住键)。在组织方面,以这种方式设置它似乎有点奇怪。我可以看到输入绑定触发两次的情况。
我还可以列出我想要一直存在的所有内置命令,即使用户设置了冲突的组合键,并禁用其余组合。这似乎是一个坏主意,因为它会非常费力,而且还可能会弄乱我无法预料的事情。
也许有一种方法可以计算出哪些内置命令会与当前输入绑定冲突并禁用它们,每次用户设置绑定时都要计算?
我还在学习MVVM和WPF,所以我怀疑我可能会遗漏一些明显的东西,或者只是以错误的方式看待它。任何帮助将不胜感激。
编辑:
有人建议我的问题与this一个问题重复。我已经回答了这个问题并确定所使用的方法肯定是朝着正确方向迈出的一步。我可以使用附加的对象来实现PreviewKeyDown处理,而不会丢失XAML中的InputBindings功能。但是,我确实有一些顾虑。
似乎解决方案是将InputBindings移动到UserControl,并实现一个可以处理PreviewKeyDown的附加对象。我的UserControl中有多个TextBox,它们需要自己的一组InputBindings,如果它们被移动到UserControl级别,其中一些会相互冲突。
我只能得出结论,它离开TextBox的原因是附加的对象由于某种原因无法直接应用于TextBox。如果我要尝试这个,我是否必须创建一个包含元素,该元素具有附加对象以保存每个TextBox?为什么TextBox不能使用附加的对象本身?