当TextBox具有焦点时,UserControl中的KeyBinding不起作用

以下情况。 我有一个用五个键绑定的用户控件。 当TextBox具有焦点时,UserControl的键绑定停止点燃。

有没有办法解决这个“问题”?

<UserControl.InputBindings> <KeyBinding Key="PageDown" Modifiers="Control" Command="{Binding NextCommand}"></KeyBinding> <KeyBinding Key="PageUp" Modifiers="Control" Command="{Binding PreviousCommand}"></KeyBinding> <KeyBinding Key="End" Modifiers="Control" Command="{Binding LastCommand}"></KeyBinding> <KeyBinding Key="Home" Modifiers="Control" Command="{Binding FirstCommand}"></KeyBinding> <KeyBinding Key="F" Modifiers="Control" Command="{Binding SetFocusCommand}"></KeyBinding> </UserControl.InputBindings> <TextBox Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"> <TextBox.InputBindings> <KeyBinding Gesture="Enter" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl }}, Path=DataContext.FilterCommand}"></KeyBinding> </TextBox.InputBindings> </TextBox> 

看来function键( F1等)和ALT + [键]工作。 我认为CTRLSHIFT修饰符以某种方式阻止事件冒泡到UserControl。

一些input绑定工作的原因是有些不需要的是TextBox控件捕获并处理一些键绑定。 例如,它处理粘贴的CTRL + V ,转到文本开头的CTRL + Home ,另一方面CTRL + F3等其他组合键不能被TextBox处理,所以它们会泡向上。

如果你只是想禁用TextBox的input绑定,那很简单 – 你可以使用ApplicationCommands.NotACommand命令,这将禁用默认行为。 例如,在下面的情况下,粘贴CTRL + V将被禁用:

 <TextBox> <TextBox.InputBindings> <KeyBinding Key="V" Modifiers="Control" Command="ApplicationCommands.NotACommand" /> </TextBox.InputBindings> </TextBox> 

然而,让它起泡给用户控制是有点棘手。 我的build议是创build一个将应用于UserControl的附加行为,注册到其PreviewKeyDown事件,并在到达TextBox之前根据需要执行其input绑定。 当input绑定被执行时,这将优先于UserControl。

我写了一个基本的行为来实现这个function,让你开始:

 public class InputBindingsBehavior { public static readonly DependencyProperty TakesInputBindingPrecedenceProperty = DependencyProperty.RegisterAttached("TakesInputBindingPrecedence", typeof(bool), typeof(InputBindingsBehavior), new UIPropertyMetadata(false, OnTakesInputBindingPrecedenceChanged)); public static bool GetTakesInputBindingPrecedence(UIElement obj) { return (bool)obj.GetValue(TakesInputBindingPrecedenceProperty); } public static void SetTakesInputBindingPrecedence(UIElement obj, bool value) { obj.SetValue(TakesInputBindingPrecedenceProperty, value); } private static void OnTakesInputBindingPrecedenceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((UIElement)d).PreviewKeyDown += new KeyEventHandler(InputBindingsBehavior_PreviewKeyDown); } private static void InputBindingsBehavior_PreviewKeyDown(object sender, KeyEventArgs e) { var uielement = (UIElement)sender; var foundBinding = uielement.InputBindings .OfType<KeyBinding>() .FirstOrDefault(kb => kb.Key == e.Key && kb.Modifiers == e.KeyboardDevice.Modifiers); if (foundBinding != null) { e.Handled = true; if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) { foundBinding.Command.Execute(foundBinding.CommandParameter); } } } } 

用法:

 <UserControl local:InputBindingsBehavior.TakesInputBindingPrecedence="True"> <UserControl.InputBindings> <KeyBinding Key="Home" Modifiers="Control" Command="{Binding MyCommand}" /> </UserControl.InputBindings> <TextBox ... /> </UserControl> 

希望这可以帮助。

阿迪·莱斯特的解决scheme运作良好。 这里有一个类似的解决scheme使用行为 C#代码:

 public class AcceptKeyBinding : Behavior<UIElement> { private TextBox _textBox; /// <summary> /// Subscribes to the PreviewKeyDown event of the <see cref="TextBox"/>. /// </summary> protected override void OnAttached() { base.OnAttached(); _textBox = AssociatedObject as TextBox; if (_textBox == null) { return; } _textBox.PreviewKeyDown += TextBoxOnPreviewKeyDown; } private void TextBoxOnPreviewKeyDown(object sender, KeyEventArgs keyEventArgs) { var uielement = (UIElement)sender; var foundBinding = uielement.InputBindings .OfType<KeyBinding>() .FirstOrDefault(kb => kb.Key == keyEventArgs.Key && kb.Modifiers == keyEventArgs.KeyboardDevice.Modifiers); if (foundBinding != null) { keyEventArgs.Handled = true; if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) { foundBinding.Command.Execute(foundBinding.CommandParameter); } } } /// <summary> /// Unsubscribes to the PreviewKeyDown event of the <see cref="TextBox"/>. /// </summary> protected override void OnDetaching() { if (_textBox == null) { return; } _textBox.PreviewKeyDown -= TextBoxOnPreviewKeyDown; base.OnDetaching(); } } 

而XAML:

 <TextBox> <TextBox.InputBindings> <KeyBinding Key="Enter" Modifiers="Shift" Command="{Binding CommandManager[ExecuteCommand]}" CommandParameter="{Binding ExecuteText}" /> </TextBox.InputBindings> <i:Interaction.Behaviors> <behaviours:AcceptKeyBinding /> </i:Interaction.Behaviors> </TextBox> 
 <UserControl.Style> <Style TargetType="UserControl"> <Style.Triggers> <Trigger Property="IsKeyboardFocusWithin" Value="True"> <Setter Property="FocusManager.FocusedElement" Value=" {Binding ElementName=keyPressPlaceHoler}" /> </Trigger> </Style.Triggers> </Style> </UserControl.Style> 

keyPressPlaceHoler是目标uielement的容器名称

请记住在usercontrol中设置Focusable="True"

除了Adi Lester(非常有帮助)的回答,我想build议一些改进/扩展,帮助我实现。

Gesture.Matches

foundBinding也可以通过调用Gesture.Matches完成。 将foundBinding Linq查询更改为以下内容:

 KeyBinding foundBinding = ((UIElement)this).InputBindings .OfType<KeyBinding>() .FirstOrDefault(inputBinding => inputBinding.Gesture.Matches(sender, eventArgs)); 

MouseBinding

此外,你也可以定义MouseBindings。

 <MouseBinding Command="{Binding DataContext.AddInputValueCommand, ElementName=root}" CommandParameter="{Binding}" Gesture="Shift+MiddleClick" /> 

然后,您还需要订阅PreviewMouseEvents,例如PreviewMouseUp和PreviewMouseDoubleClick。 这个实现和KeyBindings几乎是一样的。

 private void OnTextBoxPreviewMouseUp(object sender, MouseButtonEventArgs eventArgs) { MouseBinding foundBinding = ((UIElement)this).InputBindings .OfType<MouseBinding>() .FirstOrDefault(inputBinding => inputBinding.Gesture.Matches(sender, eventArgs)); if (foundBinding != null) { eventArgs.Handled = true; if (foundBinding.Command.CanExecute(foundBinding.CommandParameter)) { foundBinding.Command.Execute(foundBinding.CommandParameter); } } }