关于wpf:如果ItemTemplate中的TextBox获得焦点,则选择ListBoxItem

Select ListBoxItem if TextBox in ItemTemplate gets focus

我在ListBox类中添加了DataTemplate以将集合绑定到:

1
2
3
4
5
6
7
8
9
10
11
<ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276"
         SelectionChanged="lstEmails_SelectionChanged">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Label Visibility="Hidden" Content="{Binding ID}"></Label>
                <TextBox Width="200"  Text="{Binding EmailAddress}"></TextBox>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

这正是我想要的。 尽管单击TextBox时,ListBox不会自动将关联的ListItem设置为Selected。 我可以在代码中做到这一点,但我更希望将其用作组件(届时毫无意外)。

关于如何实现这一目标的任何想法?

这似乎不起作用,它不会让我单击任何东西。 我错过了什么吗? 这是我的新XAML。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<UserControl.Resources>
    <!--<TextBox x:Key="TB" x:Name="TextBoxInsideListBoxItemTemplate">
        <TextBox.Style>-->
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="IsHitTestVisible" Value="False" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
                                                     Value="True">
                        <Setter Property="IsHitTestVisible" Value="True" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        <!--</TextBox.Style>
    </TextBox>-->
</UserControl.Resources>
<Grid>
    <ListBox x:Name="lstEmails" Height="259" Margin="12,0,12,41" Width="276" SelectionChanged="lstEmails_SelectionChanged">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <!--<Label Visibility="Hidden" Content="{Binding ID}"></Label>-->
                    <TextBox Width="220" Text="{Binding EmailAddress}">
                    </TextBox>
                    <!--<TextBox Width="220" Text="{Binding EmailAddress}" GotFocus="TextBox_GotFocus"></TextBox>-->
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Width="20" Margin="12,0,0,12" Name="btnAdd" VerticalAlignment="Bottom" Click="btnAdd_Click" Height="23" HorizontalAlignment="Left">+</Button>
    <Button Width="20" HorizontalAlignment="Left" Margin="30,0,0,12" Name="btnRemove" VerticalAlignment="Bottom" Click="btnRemove_Click" Height="23">-</Button>
    <Button Height="23" HorizontalAlignment="Right" Margin="0,0,12,12" Name="btnApply" VerticalAlignment="Bottom" Width="49" Click="btnApply_Click">Apply</Button>
</Grid>

我认为点击两次是好的功能。


您可以在ItemContainerStyle中的属性IsKeyboardFocusWithin上触发,并将IsSelected设置为true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
                <DataTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="(ListBoxItem.IsSelected)">
                                <DiscreteBooleanKeyFrame KeyTime="0" Value="True"/>
                            </BooleanAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</ListBox.ItemContainerStyle>

您也可以使用Setter而不是单帧动画,但是一旦焦点离开ListBox,选择将再次丢失:

1
2
3
4
5
6
7
8
9
<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Self}}" Value="True">
                <Setter Property="IsSelected" Value="True"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</ListBox.ItemContainerStyle>


如果您有多个ListBox实例,则可以考虑使用自定义列表框(通过从ListBox派生它)。请参阅此处的说明。

或者,如果您只有1个(或数量很少的)如ListBox,并且不想为此创建单独的类,请使用此技巧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<TextBox x:Name="TextBoxInsideListBoxItemTemplate" ... >

    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="IsHitTestVisible" Value="False" />
            <Style.Triggers>
                <DataTrigger
                        Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor,
                    AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}"
                        Value="True">
                    <Setter Property="IsHitTestVisible" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>

</TextBox>

请注意,您必须再次单击以编辑TextBox中的文本(对我来说,这实际上很酷)。


我遇到的情况是,选择列表框项目会更改其布局,因此在释放鼠标按钮之前,控件可能已从光标移开。如果我想将所有内容都保留在xaml中,我发现没有比在Storyboard中稍微延迟更好的解决方案了。

更重要的是,对于重复选择,GotKeyboardFocus似乎比IsKeyboardFocusWithin更好。

1
2
3
4
5
6
7
8
9
<EventTrigger RoutedEvent="GotKeyboardFocus">
    <BeginStoryboard>
        <Storyboard>
            <BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="IsSelected">
                <DiscreteBooleanKeyFrame KeyTime="00:00:00.3" Value="True"/>
            </BooleanAnimationUsingKeyFrames>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>