[英]WPF: KeyBinding for Tab, Swallows Tab and Doesn't Pass It Along
我有一個文本框,里面有這個: <KeyBinding Command="{Binding MyCommand}" Key="Tab"/>
問題是它吞下了 Tab 並且不跳到下一個控件。 如何捕獲文本框的 Tab 並仍然保留 Tab 鍵順序中的下一個控件? 編輯:我也在使用 MVVM 並且 MyCommand 在 ViewModel 代碼中,所以這就是我需要重新拋出 Tab 的地方。
這很容易實現,只是不要為此使用 KeyBinding。 處理您的 TextBox 的 OnKeyDown 事件:
<TextBox KeyDown="UIElement_OnKeyDown" ...
然后在代碼隱藏中,每當按下 Tab 時執行您的命令。 與 KeyBinding 不同,這不會吞下 TextInput 事件,因此它應該可以工作。
private void OnKeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Tab:
// Execute your command. Something similar to:
((YourDataContextType)DataContext).MyCommand.Execute(parameter:null);
break;
}
}
鑒於您的問題作為純粹的 XAML 解決方案,我找不到將焦點設置到控件的方法。
我選擇創建一個 attacted 屬性,然后通過綁定將焦點從與 ViewModel 中的 KeyBinding 關聯的 Command 設置為下一個控件。
這是視圖:
<Window x:Class="WarpTab.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:WarpTab.Commands"
xmlns:Views="clr-namespace:WarpTab.Views"
xmlns:local="clr-namespace:WarpTab.ViewModels"
Title="Main Window" Height="400" Width="800">
<Window.Resources>
<c:CommandReference x:Key="MyCommandReference" Command="{Binding MyCommand}" />
</Window.Resources>
<DockPanel>
<ScrollViewer>
<WrapPanel >
<TextBox Text="First text value" >
<TextBox.InputBindings>
<KeyBinding Command="{StaticResource MyCommandReference}" Key="Tab"/>
</TextBox.InputBindings>
</TextBox>
<TextBox Text="Next text value" local:FocusExtension.IsFocused="{Binding FocusControl}" />
<Button Content="My Button" />
</WrapPanel>
</ScrollViewer>
</DockPanel>
</Window>
這是視圖模型:
using System.Windows.Input;
using WarpTab.Commands;
namespace WarpTab.ViewModels
{
public class MainViewModel : ViewModelBase
{
public ICommand MyCommand { get; set; }
public MainViewModel()
{
MyCommand = new DelegateCommand<object>(OnMyCommand, CanMyCommand);
}
private void OnMyCommand(object obj)
{
FocusControl = true;
// process command here
// reset to allow tab to continue to work
FocusControl = false;
return;
}
private bool CanMyCommand(object obj)
{
return true;
}
private bool _focusControl = false;
public bool FocusControl
{
get
{
return _focusControl;
}
set
{
_focusControl = value;
OnPropertyChanged("FocusControl");
}
}
}
}
這是我在以下答案中找到的用於定義附加屬性的代碼。
using System.Windows;
namespace WarpTab.ViewModels
{
public static class FocusExtension
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof(bool), typeof(FocusExtension),
new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
private static void OnIsFocusedPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
if ((bool)e.NewValue)
{
uie.Focus(); // Don't care about false values.
}
}
}
}
為什么不在命令處理程序中使用此代碼?
private void MyCommandHandler(){
// Do command's work here
TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
request.Wrapped = true;
control.MoveFocus(request);
}
這基本上就是“Tab”所做的,所以如果你也這樣做,你就可以開始了。 (當然,如果您有帶有 Shift-Tab 的命令,請反轉方向。
我實際上把它包裝成一個像這樣的擴展方法......
public static class NavigationHelpers{
public static void MoveFocus(this FrameworkElement control, FocusNavigationDirection direction = FocusNavigationDirection.Next, bool wrap = true) {
TraversalRequest request = new TraversalRequest(direction);
request.Wrapped = wrap;
control.MoveFocus(request);
}
}
...意味着先前的代碼變得更加簡單,就像這樣......
private void MyCommandHandler(){
// Do command's work here
Control.MoveFocus();
}
......如果你不知道當前聚焦的控件是什么,你可以這樣做......
(Keyboard.FocusedElement as FrameworkElement).MoveFocus();
希望這可以幫助! 如果是這樣,非常感謝您投票給我或將其標記為已接受!
遇到了同樣的問題,遇到了這個線程,我花了一段時間才找到最佳答案。 參考: 在特定鍵上使用 EventTrigger定義此類:
using System; using System.Windows.Input; using System.Windows.Interactivity;
public class KeyDownEventTrigger : EventTrigger
{
public KeyDownEventTrigger() : base("KeyDown")
{
}
protected override void OnEvent(EventArgs eventArgs)
{
var e = eventArgs as KeyEventArgs;
if (e != null && e.Key == Key.Tab)
{
this.InvokeActions(eventArgs);
}
}
}
文本框的 xaml:
<TextBox x:Name="txtZip"
Text="{Binding Zip, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding ZipLookup.GetAddressByZipKeyCommand}" CommandParameter="{Binding ElementName=txtZip, Path=Text}" />
</TextBox.InputBindings>
<i:Interaction.Triggers>
<iCustom:KeyDownEventTrigger EventName="KeyDown">
<i:InvokeCommandAction Command="{Binding ZipLookup.GetAddressByZipKeyCommand}" CommandParameter="{Binding ElementName=txtZip, Path=Text}" />
</iCustom:KeyDownEventTrigger>
</i:Interaction.Triggers>
</TextBox>
在您的窗口或用戶控件根標記中包含以下屬性:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:iCustom="clr-namespace:[NAMESPACE FOR CUSTOM KEY DOWN CLASS]"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.