Wpf ControlTemplate中控件的焦点处理

Wpf ControlTemplate中控件的焦点处理,wpf,focus,controltemplate,Wpf,Focus,Controltemplate,当您编写自己的控件(其控件模板中包含控件)时,管理焦点的正确方法是什么 假设我们有一个CustomControl,它的ControlTemplate中有两个文本框。作为用户和开发人员,我期望以下行为: 调用customControl.Focus()时,模板中的第一个文本框应接收焦点 使用Tab/Shift+Tab向前和向后移动焦点预期会起作用,这意味着: 2.1如果用户在customControl之前的控件中按下具有焦点的Tab键,则焦点应移动到customControl的第一个文本框 2.2

当您编写自己的控件(其控件模板中包含控件)时,管理焦点的正确方法是什么


假设我们有一个CustomControl,它的ControlTemplate中有两个文本框。作为用户和开发人员,我期望以下行为:

  • 调用customControl.Focus()时,模板中的第一个文本框应接收焦点

  • 使用Tab/Shift+Tab向前和向后移动焦点预期会起作用,这意味着:

  • 2.1如果用户在customControl之前的控件中按下具有焦点的Tab键,则焦点应移动到customControl的第一个文本框

    2.2如果用户在自定义控件的第一个文本框中按下具有焦点的Shift+Tab键,则焦点应移动到自定义控件之前的任何控件


    我已经试过了:

    a。将CustomControl设置为Focusable=false将启用条件2。但禁用条件1

    b。在StackOverflow上,如何将焦点移动到控件模板内的控件的问题出现了很多次。始终提出以下解决方案:

    <Trigger Property="IsFocused" Value="True">
      <Setter TargetName="PART_TextBox1" Property="FocusManager.FocusedElement" Value="{Binding ElementName=PART_TextBox1}" />
    </Trigger>
    
    
    
    此解决方案启用条件1和2.1,但破坏条件2.2


    感谢您的帮助:)

    您可以使用第二个选项(“代码>IsFocused属性上的触发器”),只需将CustomControl的
    IsTabStop
    属性设置为
    False
    即可满足条件2.2。不过,此解决方案的一个大缺陷是,通过将
    IsTabStop
    属性设置回
    True
    ,可以很容易地将其撤消

    实现目标的另一种方法是放下触发器,处理控件代码中的焦点更改,如下所示:

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        base.OnGotKeyboardFocus(e);
        if (e.NewFocus == this)
        {
            if (object.ReferenceEquals(e.OldFocus, Template.FindName("PART_TextBox1", this)))
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
            else
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }
    

    我还建议在模板中的任何可聚焦控件上设置属性
    IsTabStop={TemplateBinding IsTabStop}
    TabIndex={TemplateBinding TabIndex}
    ,以便在控件上设置这些属性时,它仍然保持内部导航顺序,并防止/允许使用TAB键导航到每个内部控件。

    您可以使用第二个选项(触发
    IsFocused
    属性),只需将CustomControl的
    IsTabStop
    属性设置为
    False
    ,即可满足条件2.2。不过,此解决方案的一个大缺陷是,通过将
    IsTabStop
    属性设置回
    True
    ,可以很容易地将其撤消

    实现目标的另一种方法是放下触发器,处理控件代码中的焦点更改,如下所示:

    protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
    {
        base.OnGotKeyboardFocus(e);
        if (e.NewFocus == this)
        {
            if (object.ReferenceEquals(e.OldFocus, Template.FindName("PART_TextBox1", this)))
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));
            else
                MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }
    

    我还建议在模板中的任何可聚焦控件上设置属性
    IsTabStop={TemplateBinding IsTabStop}
    TabIndex={TemplateBinding TabIndex}
    ,以便在控件上设置这些属性时,它仍然保持内部导航顺序,并防止/允许使用TAB键导航到每个内部控件。

    值得一读:逻辑焦点处理感谢您的链接。我认为我理解逻辑焦点,引入焦点范围并不能解决问题,在我看来也不是正确的方法。或者你的链接背后还有其他意图吗?没有特别的意图,但是当涉及到焦点相关的事情时,逻辑范围经常被忽略。更新链接:值得一读:逻辑焦点处理感谢你的链接。我认为我理解逻辑焦点,引入焦点范围并不能解决问题,在我看来也不是正确的方法。或者你的链接背后还有其他意图吗?没有特别的意图,但是当涉及到焦点相关的事情时,逻辑范围通常会被忽略。更新链接: