带自定义控件的WPF标签顺序?

ElH*_*aix 3 wpf custom-controls tab-ordering custom-properties

我有一个WPF页面,其中包含几个带有Tab键顺序设置的开箱即用控件.

我有一个自定义控件(NumericSpinner),其中包含:border/grid/text box/2 Repeatbuttons(向上/向下).

两个问题:

1)当我在自定义选择器控件的文本框中时,我无法将其标记为页面上的其他控件.但是,在单击其中一个向上/向下箭头后,我可以切换到其他控件.

2)我无法按顺序进入自定义控件的文本框.只有在我通过所有控件选项卡后,光标才会落在文本框中(并且不能标记出来).

语境:

<ComboBox Margin="97,315,21,0" Name="txtdweldatcdu" Style="{StaticResource fieldComboBoxStyle}" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" VerticalAlignment="Top" TabIndex="10" />
    <WpfControls:NumericSpinner Margin="97,338,21,0" Name="txtdweldatpctcomplete" HorizontalAlignment="Left" VerticalAlignment="Top" AllowNegativeValues="True" MaxValue="100" TabIndex="11" />
    <ComboBox Margin="97,363,21,0" Name="txtdweldatclass" Style="{StaticResource fieldComboBoxStyle}" IsSynchronizedWithCurrentItem="True" HorizontalAlignment="Left" VerticalAlignment="Top" TabIndex="12" />
Run Code Online (Sandbox Code Playgroud)

自定义控件的一部分:

 <Border BorderThickness="1" BorderBrush="Gray" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="20" Width="117">
        <Grid Margin="0">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="98"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <TextBox Name="valueText" 
                     BorderThickness="0" 
                     Grid.RowSpan="2"
                     Style="{StaticResource spinnerTextBoxStyle}"
                     PreviewKeyDown="valueText_PreviewKeyDown"
                     PreviewTextInput="valueText_PreviewTextInput"
                     TextChanged="valueText_TextChanged"
                     IsReadOnly="{Binding ElementName=Spinner, Path=IsReadOnly}"
                     Text="{Binding ElementName=Spinner, Path=Value, Mode=TwoWay}"
                     KeyboardNavigation.IsTabStop="True"
                     AcceptsTab="True"/>
            <RepeatButton Name="upButton" Style="{StaticResource spinnerRepeatButtonStyle}" Click="upButton_Click"  Grid.Column="1" Grid.Row="0" Height="10" Width="18" VerticalAlignment="Top" HorizontalAlignment="Right" HorizontalContentAlignment="Center">
                <Polygon  HorizontalAlignment="Center" Points="3,2 2,3 4,3"  Fill="Black"  Stretch="Uniform"  Stroke="Black"  StrokeThickness="0" />
            </RepeatButton>
            <RepeatButton Name="downButton" Style="{StaticResource spinnerRepeatButtonStyle}" Click="downButton_Click"  Grid.Column="1" Grid.Row="1" Height="10" Width="18" VerticalAlignment="Top" HorizontalAlignment="Right" HorizontalContentAlignment="Center">
                <Polygon  HorizontalAlignment="Center" Points="2,2 4,2 3,3"  Fill="Black"  Stretch="Uniform"  Stroke="Black"  StrokeThickness="0" />
            </RepeatButton>
        </Grid>
    </Border>
Run Code Online (Sandbox Code Playgroud)

自定义控件由xaml和代码隐藏文件组成.

包含所有控件的父xaml页面是动态加载的,不包含代码隐藏.

在自定义控件的构造函数中,我将以下内容设置为测试:

    valueText.TabIndex = 3;
    this.TabIndex = 3;
Run Code Online (Sandbox Code Playgroud)

第四次我选项卡,我实际上把光标放到文本字段中,但是我不能将它标记出来.

考虑到这一点,第一步是创建一个控制参数,我可以传递一个在控件的代码隐藏中设置的Tab键序号.

我创建了一个CustomTabIndex属性:

/// <summary>
/// Custom tab index property
/// </summary>
public int CustomTabIndex
{
    get { return (int)GetValue(CustomTabIndexProperty); }
    set { SetValue(CustomTabIndexProperty, value); }
}

public static readonly DependencyProperty CustomTabIndexProperty = 
    DependencyProperty.Register("CustomTabIndex", typeof(int), typeof(NumericSpinner));
Run Code Online (Sandbox Code Playgroud)

在xaml中,当我尝试设置CustomTabIndex ="3"时,我收到错误:

在'NumericSpinner'类型中找不到属性'CustomTabIndex'.

一些援助将不胜感激.

Hax*_*lit 6

我有第一个答案...在CustomControl的静态构造函数中添加以下内容

KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
Run Code Online (Sandbox Code Playgroud)

这应该允许您进出控件,并允许您为自定义控件的每个子项设置选项卡索引.

至于你的第二个问题,我正在努力搞清楚同样的事情.我认为它必须与您的自定义控件具有Focusable = False的事实有关.但将此设置为true将使控件获得焦点而不是实际的孩子.我认为可能需要的是您的CustomControl上的事件处理程序,用于GotFocus事件.当控件获得焦点时,然后执行

this.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
Run Code Online (Sandbox Code Playgroud)

这应该将焦点移到子元素.

当我找到正确的方法时,我会发布一个跟进.

更新

所以对你的第二点.

确保将focusable设置为false,并将TabNavigationProperty设置为控件的静态构造函数

FocusableProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(false));
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
Run Code Online (Sandbox Code Playgroud)

这将允许控件按预期工作并遵守控件上的Tab顺序以及所有子项.确保您的样式中没有设置Focusable或TabNavigation属性.

劳尔