簡體   English   中英

WPF:選項卡的鍵綁定,吞下選項卡並且不傳遞它

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM