下面的情况。 我有一个用户控件有五个键绑定。 当文本框具有焦点的用户控件的按键绑定停止射击..
有没有办法来解决这个“问题”?
<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>
这似乎功能键(F1等)和ALT + [关键]做的工作。 我相信CTRL和SHIFT修饰在某种程度上向上冒泡到用户控件的“堵”的事件。
之所以一些输入绑定工作,和一些不就是TextBox控件捕获并处理一些键绑定。 例如,它可以处理CTRL + V进行粘贴,CTRL + 主页要去文本等,如Ctrl + F3,另一方面其他键组合不被处理的文本框的开始,所以他们会泡起来。
如果你只是想禁用文本框的输入绑定,这将是简单的-你可以使用ApplicationCommands.NotACommand
命令,这将禁用默认行为。 例如,在下面的情况下,粘贴与CTRL + V将被禁用:
<TextBox>
<TextBox.InputBindings>
<KeyBinding Key="V" Modifiers="Control" Command="ApplicationCommands.NotACommand" />
</TextBox.InputBindings>
</TextBox>
然而,使其冒泡给用户控制是有点麻烦。 我的建议是创建一个将被应用到该用户控件附加的行为,登记其PreviewKeyDown
事件,他们到达之前文本框在必要时执行其输入绑定。 这将输入绑定执行时的用户控件给予优先。
我写了实现这一功能,让你开始一个基本的行为:
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>
希望这可以帮助。
阿迪·莱斯特的解决方案效果很好。 下面是使用行为类似的解决方案。 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>
除了阿迪莱斯特他(非常有用)的答案,我想提出一些改进/扩展,帮助我与我的实现。
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。 实现是那么几乎一样的键绑定。
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);
}
}
}
<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
记得设置Focusable="True"
的用户控件