2

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


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

  1. 调用 customControl.Focus() 时,模板中的第一个 TextBox 应获得焦点。

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

2.1 如果用户在customControl 之前按下具有焦点的Tab 键,那么焦点应该移动到customControl 的第一个文本框。

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


以下我已经尝试过:

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

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

<Trigger Property="IsFocused" Value="True">
  <Setter TargetName="PART_TextBox1" Property="FocusManager.FocusedElement" Value="{Binding ElementName=PART_TextBox1}" />
</Trigger>

此解决方案启用条件 1 和 2.1,但破坏条件 2.2。

谢谢你的帮助 :)

4

1 回答 1

4

您可以使用第二个选项(属性触发器)并通过简单地将CustomControlIsFocused的属性设置为来满足条件 2.2 。不过,这个解决方案的最大缺陷是可以通过将属性设置回.IsTabStopFalseIsTabStopTrue

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

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 键导航到每个内部控件.

于 2014-04-21T08:24:11.027 回答