如何防止使用控件模板创建的WPF自定义控件在其周围绘制焦点



我正在开发一个来自control的自定义控件,并使用ControlTemplate定义。在去掉所有的花里胡哨之后,控件只显示了四个textbox:

<Style TargetType="{x:Type local:MyControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyControl}">
                <StackPanel Orientation="Horizontal">
                    <TextBox/>
                    <TextBox/>
                    <TextBox/>
                    <TextBox/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

问题是控件能够接收键盘焦点并在其周围绘制焦点矩形(不是一个textbox,而是所有textbox)。这在窗口中导航控件时增加了一个不必要的制表符。

将自定义控件的Focusible设置为false(使用样式中的setter)解决了这个问题,但这样的解决方案远非完美,因为使用该控件的开发人员可能会将Focusible设置为true,这会破坏制表符停止的行为。

我可以响应控件的GotKeyboardFocus事件,并在整个控件接收焦点时将焦点给予第一个文本框,但这将不能正常工作,当Tab返回(使用Shift+Tab)时,第一个文本框将接收焦点,而在这种情况下,最后一个文本框应该首先聚焦。

我怎么能防止整个自定义控件接受键盘焦点,但允许子文本框正常作为制表位?

我将创建一个实际的UserControl并在那里封装焦点管理。因为Xaml通过Style只能让你到此为止……

下面是一个UserControl +它的用法/测试在主窗口的快速示例。你会注意到聚焦的矩形不再出现了。为了简单起见,我没有包括数据绑定/视图模型等(因为你的问题不是关于那个)
<UserControl x:Class="WpfApplication1.MyControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         IsVisibleChanged="OnIsVisibleChanged" >
<StackPanel Orientation="Horizontal">
    <TextBox x:Name="txtA">txtA</TextBox>
    <TextBox>txtB</TextBox>
    <TextBox>txtC</TextBox>
    <TextBox>txtD</TextBox>
</StackPanel>

后面的代码中将焦点设置为可见性的第一个文本框
namespace WpfApplication1
{
public partial class MyControl : UserControl
{
    private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (IsVisible && IsEnabled)
        {
            Keyboard.Focus(null);
            Keyboard.Focus(txtA);
        }
    }
    public MyControl()
    {
        InitializeComponent();
    }
}

}

在我的小测试中,当运行tab: 时,我将MyControl放在两个其他文本框之间。
<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TextBox>txt1</TextBox>
    <c:MyControl/>
    <TextBox>txt2</TextBox>
</StackPanel>

最新更新