我有一个WPF页面,其中包含几个带有Tab键顺序设置的开箱即用控件。
我有一个自定义控件(NumericSpinner),其中包含:border / grid / text box / 2 Repeatbuttons(up / down)。
两个问题:
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" />
自定义控件的一部分:
<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>
自定义控件由xaml和代码隐藏文件组成。
包含所有控件的父xaml页面是动态加载的,不包含代码隐藏。
在自定义控件的构造函数中,我将以下内容设置为测试:
valueText.TabIndex = 3;
this.TabIndex = 3;
第四次我选择,我实际上将光标放入文本字段,但是我无法将其标记出来。
考虑到这一点,第一步是创建一个控制参数,我可以传递一个在控件的代码隐藏中设置的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));
在xaml中,当我尝试设置CustomTabIndex =“3”时,收到错误:
属性'CustomTabIndex'不是 在“NumericSpinner”类型中找到。
一些帮助将不胜感激。
答案 0 :(得分:6)
我对第一个问题有答案...... 在CustomControl的静态构造函数中添加以下
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
这应该允许您在控件中输入和输出,并允许您为自定义控件的每个子项设置选项卡索引。
关于你的第二个问题,我正在努力搞清楚同样的事情。我认为它必须与您的自定义控件具有Focusable = False的事实有关。但将此设置为true将使控件获得焦点而不是实际的孩子。我认为可能需要的是您的CustomControl上的事件处理程序,用于GotFocus事件。当控件获得焦点时,请执行
this.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
并且应该将焦点移动到子元素。
当我找到正确的方法时,我会发布一个跟进。
<强>更新强>
所以第二点。
确保将focusable设置为false,并将TabNavigationProperty设置为控件的静态构造函数
FocusableProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(false));
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
这将允许控件按预期工作并遵守控件上的Tab顺序以及所有子项。确保您的样式中没有设置Focusable或TabNavigation属性。
劳尔
答案 1 :(得分:4)
我没有完整的解决方案,但应检查以下四项内容以进行制表循环:
我可以想象IsFocusScope会很有趣。
答案 2 :(得分:0)
Raul回答了主要问题 - 能够在自定义控件的文本框中进行选项卡。第二个问题是无法从文本框中跳出标签。
此控件的问题在于其文本框包含一个按键处理程序:
PreviewKeyDown="valueText_PreviewKeyDown"
处理程序只允许在文本框中按下某些键:
/// <summary>
/// Since this event handler traps keystrokes within the control, in order to facilitate tabbing order, allowing the
/// tab key press must be enabled
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void valueText_PreviewKeyDown(object sender, KeyEventArgs e)
{
KeyConverter converter = new KeyConverter();
string key = converter.ConvertToString(e.Key);
int index = ((TextBox)sender).CaretIndex;
if (key != null)
{
if (AllowNegativeValues && (e.Key == Key.Subtract || e.Key == Key.OemMinus))
{
e.Handled = (valueText.Text.Contains('-') || index > 0) == true;
}
else if (AllowDecimal && (e.Key == Key.OemPeriod || e.Key == Key.Decimal))
{
e.Handled = valueText.Text.Contains('.') == true;
}
else
e.Handled = ((((e.Key >= Key.D0) && (e.Key <= Key.D9) && (e.KeyboardDevice.Modifiers != ModifierKeys.Shift))
|| ((e.Key >= Key.NumPad0) && (e.Key <= Key.NumPad9) && (e.KeyboardDevice.Modifiers != ModifierKeys.Shift))
|| e.Key == Key.Left || e.Key == Key.Right
|| e.Key == Key.Back || e.Key == Key.Delete
|| e.Key == Key.Tab) == false);
}
else
e.Handled = true;
}
我只需要添加允许的TAB键击,自定义控件就可以了:
e.Key == Key.Tab
答案 3 :(得分:0)
我已尝试使用所选答案的GotFocus
事件,但它对我不起作用,它似乎完全禁用了标签导航,即使确实选择了第一个TabStop
。<登记/>
对我有用的是使用WindowActivated
事件并在那里使用相同的命令:
MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
我希望它可以帮助别人。
答案 4 :(得分:0)
除非我们想通过 Alt + hotkey 使用标签来集中我们的控制,否则HaxElit的回答是有效的:
<!-- Alt + C selects numCount -->
<Label Target="{Binding ElementName=numCount}">Elements _Count:</Label>
<local:NumericSpinner x:Name="numCount"/>
所以我的最终解决方案如下:
static NumericSpinner()
{
// Next line prevents focusing our wrapper parent control. The problem with that is that
// it prevents Label controls to select our control by Alt+<hotkey>
//FocusableProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(false));
// Next line specifies that the children controls have their own tab subtree so a deep
// traversal is performed when our control is focused
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(NumericSpinner), new FrameworkPropertyMetadata(KeyboardNavigationMode.Local));
}
// our wrapper control is focused invisibly. We must relocate the focus.
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
// Next line moves the focus either forward (to out first inner child)
// or backward if Shift+TAB is pressed (to the previous control)
MoveFocus(new TraversalRequest(Keyboard.IsKeyDown(Key.Tab) && (Keyboard.Modifiers & ModifierKeys.Shift) != 0 ? FocusNavigationDirection.Previous : FocusNavigationDirection.Next));
}