用户控制失去键盘焦点

时间:2017-06-13 01:16:39

标签: c# wpf keyboard focus

我创建了一个用户控件,我称之为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>

当用户点击按钮时,使用以下callack:

    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键,堆栈中的第二个项目就会进入编辑模式,但第一个项目会立即获得键盘焦点。谁能理解为什么会这样?

1 个答案:

答案 0 :(得分:0)

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

另外,对于检查indeces,通常希望索引为&lt;计数。所以你的索引+ 1可以==计算它是否= =计数 - 1.你不想要:

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

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

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