用户控件失去键盘焦点



我创建了一个用户控件,我称之为InputTextBox,它显示用户只有在单击控件后才能编辑的文本:

<Grid>  
<TextBox Name="box"
Text="{Binding RelativeSource={RelativeSource AncestorType=local:InputTextBlock}, Path=Text, Mode=TwoWay}"
Visibility="Hidden"
LostKeyboardFocus="box_LostKeyboardFocus"
KeyDown="box_KeyDown"/>
<Button Name="block"
Background="Transparent"
BorderThickness="0"
Click="block_Click">
<Button.Content>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=local:InputTextBlock}, Path=Text}" />
</Button.Content>
</Button>
</Grid>

当用户单击该按钮时,将使用以下卡拉克:

private void block_Click(object sender, RoutedEventArgs e)
{
StartEdit();
}
public void StartEdit()
{
box.Visibility = Visibility.Visible;
block.Visibility = Visibility.Hidden;
box.CaretIndex = box.Text.Length;
Keyboard.Focus(box);
}

控件中还处理两个更重要的事件。第一种是当控件失去键盘焦点时:

private void box_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
box.Visibility = Visibility.Hidden;
block.Visibility = Visibility.Visible;
}

另一种是当用户按 TAB 或 ENTER 键时:

private void box_KeyDown(object sender, KeyEventArgs e)
{
Key key = e.Key;
if (key == Key.Enter || key == Key.Tab)
{
RoutedEventArgs args = new RoutedEventArgs(KeyExitEvent, this, e.Key);
RaiseEvent(args);
}
}

这会引发我为此控件注册的一个名为 KeyExit 的简单路由事件。

因此,基本上,就像此控件具有两种"模式":用户只需单击控件即可激活的"编辑模式"和"视图模式",用户可以通过在 UI 键盘焦点中提供任何其他控件来返回该模式。

在我的UI中,我有一个堆栈面板,其中包含一堆这些控件 - 每个控件都包装在我创建的类中,该类在概念上类似于ListViewItem。这个想法是,当用户在堆栈面板中的某个项目内处于编辑模式并单击 TAB 或 Enter 键时,面板中的下一个控件将进入编辑模式。

所以,我有以下事件回调:

private void item_KeyExit(object sender, RoutedEventArgs e)
{
FrameworkElement obj = e.OriginalSource as FrameworkElement;
if (obj != null)
{
var listItem = VisualTreeHelperUtils.FindFirstAncestorOfType<MyListItem>(obj);
if (listItem != null)
{
int itemIndex = stackPanelList.Children.IndexOf(listItem);
MyListItem nextItem = null;
if (itemIndex == ucSortableList.Children.Count - 1)
{
nextItem = stackPanelList.Children[itemIndex+1] as MyListItem;
}
if (nextItem != null)
{
var item = nextItem.DataContent; // property I made in MyListItem that gives access to the class it wraps
InputTextBlock block = item as InputTextBlock;
if (block != null)
{
block.StartEdit();
}
}
}
}
}

一切都被正确调用,但是在完成所有操作后,我从中跳出的前一项会重新获得键盘焦点,并导致堆栈中的任何项目都处于编辑模式。因此,例如,如果堆栈中的第一项处于编辑模式,则一旦用户按 Tab 键,堆栈中的第二项将进入编辑模式,但随后第一项会立即恢复键盘焦点。有人能理解为什么会这样吗?

默认情况下,StackPanel Focusable为假。建议确保它是真的。

同样为了检查indeces,人们通常希望索引是


if (itemIndex < ...Count - 1)这样,项目索引 + 1 将始终为 <= 计数 - 1 ?

if (itemIndex == ucSortableList.Children.Count - 1) { nextItem = stackPanelList.Children[itemIndex+1] as MyListItem; }

您也可以使用box.Focus()代替Keyboard.Focus(box)但这可能不是必需的。

最新更新