简体   繁体   English

C#WPF选项卡从ListBox外部导航到ListBoxItem内部

[英]C# WPF Tab Navigate to control inside of a ListBoxItem from outside of ListBox

I have a window with version text boxes, buttons, and a ListBox that expands and contracts. 我有一个带有版本文本框,按钮和可扩展和收缩的ListBox的窗口。 Each ListBox item has multiple text boxes. 每个ListBox项都有多个文本框。 I am trying to find a way to tab navigate from outside of the the ListBox to the first TextBox in the first item for the ListBox . 我试图找到一种方法,标签从该境外导航ListBox的第一个TextBox中的第一个项目ListBox I can get it to navigate to the ListBox itself and if I hit the down arrow key it will select the first item but that is clumsy. 我可以将其导航到ListBox本身,如果按下向下箭头键,它将选择第一个项目,但这很笨拙。 I need it to tab directly from something outside the ListBox to something inside the ListBox . 我需要它直接将标签从ListBox之外的选项卡切换到ListBox内部的选项卡。

Below is some of the XAML I use for the ListBox . 以下是一些我用于ListBox的XAML。

                    <ListBox x:Name="add_users_listbox" Margin="2,116,-8,0" BorderThickness="0" Height="322" Padding="0,0,0,0"
                             HorizontalContentAlignment="Center" VerticalContentAlignment="Top" 
                             HorizontalAlignment="Center" VerticalAlignment="Top"
                             SelectionMode="Single"
                             IsTabStop="True"
                             TabIndex="1004"
                             Background="{x:Null}" BorderBrush="{x:Null}"
                             ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                             ScrollViewer.CanContentScroll="False"
                             ItemsSource="{Binding Add_User_Binding}"
                             SelectedIndex="{Binding Add_User_Selected_Index, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

                        <ListBox.Resources>
                            <Style TargetType="{x:Type ScrollBar}" BasedOn="{StaticResource ScrollBar_Rounded}"/>
                            <Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource CustomListBoxItemStyle}"/>
                            <Style TargetType="{x:Type ListBox}" >
                                <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue" />
                            </Style>
                        </ListBox.Resources>

                        <ListBox.ItemTemplate>

                            <DataTemplate>
                                <Grid Height="60" Background="Transparent"
                                      HorizontalAlignment="Center" VerticalAlignment="Top">

                                    <TextBox Height="26" Width="102" Padding="0,-1,0,1" Margin="2,2,0,0"
                                                 HorizontalAlignment="Left" VerticalAlignment="Top" HorizontalContentAlignment="Left" VerticalContentAlignment="Center"
                                                 FontFamily="Segoe UI" FontSize="16" FontWeight="Bold"
                                                 TextWrapping="NoWrap" IsReadOnlyCaretVisible="True" UndoLimit="10" AllowDrop="False" MaxLines="1"
                                                 TabIndex="{Binding First_TabIndex}"
                                                 MaxLength="20"
                                                 TextChanged="first_last_textbox_TextChanged"
                                                 PreviewTextInput="first_last_textbox_PreviewTextInput"
                                                 Text="{Binding First_Textbox, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True}">
                                    </TextBox>

                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>

                    </ListBox>

Simply make your ListBox IsTabStop="False" and the LitBoxItemStyle too. 只需使您的ListBox IsTabStop="False"和LitBoxItemStyle都可以。 I added this setter to the ListBoxItemStyle: <Setter Property="IsTabStop" Value="False"/> 我将此设置器添加到ListBoxItemStyle中: <Setter Property="IsTabStop" Value="False"/>

  <ListBox x:Name="add_users_listbox" Grid.Row="1"  BorderThickness="0" Height="322" Padding="0,0,0,0"
                         HorizontalContentAlignment="Center" VerticalContentAlignment="Top" 
                         HorizontalAlignment="Center" VerticalAlignment="Top"
                         SelectionMode="Single"
                         IsTabStop="False"
                         TabIndex="1004"
                         Background="{x:Null}" BorderBrush="{x:Null}"
                         ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                         ScrollViewer.CanContentScroll="False"
                         ItemsSource="{Binding Add_User_Binding}"
                         SelectedIndex="{Binding Add_User_Selected_Index, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

        <ListBox.Resources>
            <Style TargetType="{x:Type ScrollBar} BasedOn="{StaticResource ScrollBar_Rounded}" "/> 
            <Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource CustomListBoxItemStyle}">                     
                <Setter Property="IsTabStop" Value="False"/>
            </Style>
            <Style TargetType="{x:Type ListBox}" >
                <Setter Property="KeyboardNavigation.TabNavigation" Value="Continue" />
            </Style>
        </ListBox.Resources>

        <ListBox.ItemTemplate>

            <DataTemplate>
                <Grid Height="60" Background="Transparent"
                                  HorizontalAlignment="Center" VerticalAlignment="Top">

                    <TextBox Height="26" Width="102" Padding="0,-1,0,1" Margin="2,2,0,0"
                                             HorizontalAlignment="Left" VerticalAlignment="Top" HorizontalContentAlignment="Left" VerticalContentAlignment="Center"
                                             FontFamily="Segoe UI" FontSize="16" FontWeight="Bold"
                                             TextWrapping="NoWrap" IsReadOnlyCaretVisible="True" UndoLimit="10" AllowDrop="False" MaxLines="1"                                                  
                                             MaxLength="20"
                                             TextChanged="first_last_textbox_TextChanged"
                                             PreviewTextInput="first_last_textbox_PreviewTextInput"
                                             Text="{Binding First_Textbox, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}">
                    </TextBox>

                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>

    </ListBox>

So, this is likely NOT the ideal way to do this, but it works. 因此,这可能不是实现此目的的理想方法,但它确实有效。 First we add a bound tag to the TextBox within the DataTemplate 首先,我们在DataTemplateTextBox添加一个绑定标签

    ItemsSource="{Binding ListBox_Item_Collection}">

    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <TextBox Text="{Binding First_Textbox, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                         Tag="{Binding Index}">
                </TextBox>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>

For simplicity I bound that tag to the corresponding index in the ItemSource collection. 为简单起见,我将该标签绑定到ItemSource集合中的相应索引。

                int index = Add_User_Binding.Count;

                ListBox_Item_Collection.Add(new SomeDataType()
                {
                    Index = index,
                    The_Textbox = "Stuff in TextBox",
                });

The next step is to add a KeyDown event in the user control that comes before this one. 下一步是在此控件之前的用户控件中添加KeyDown事件。 In that event we will find the element with that tag and then use the Dispatcher to focus it. 在这种情况下,我们将找到带有该标签的元素,然后使用Dispatcher进行聚焦。

    private void Preview_TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Tab)
        {
            string tag = "0";
            IEnumerable<TextBox> elements = FindVisualChildren<TextBox>(this).Where(x => x.Tag != null && x.Tag.ToString() == tag);

            foreach (TextBox element in elements)
            {
                FocusElement(element);
            }
        }
    }

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

    private void FocusElement(IInputElement element)
    {
        if (element != null)
        {
            Dispatcher.BeginInvoke
            (System.Windows.Threading.DispatcherPriority.ContextIdle,
            new Action(delegate ()
            {
                Keyboard.Focus(element);
            }));
        }
    }

As you can see, lots of work for something that should be much simpler. 如您所见,很多工作要做的事情应该更简单。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM