Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Select ListBoxItem if TextBox in ItemTemplate gets focus

I have added a DataTemplate to a ListBox class to bind my collection to:

<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> 

This does exactly what I want it to do. Although when I click on the TextBox, the ListBox does not automatically set the associated ListItem as Selected. I could do this in code, but I would prefer to use this as a component (no surprises there then).

Any ideas on how to achieve this?


That doesn't seem to work, it won't let me click on anything. Have I missed something. Here is my new XAML.

<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>

I think the click twice bit is good functionality.

like image 266
Neil B Avatar asked Feb 03 '10 12:02

Neil B


2 Answers

You can trigger on the property IsKeyboardFocusWithin in the ItemContainerStyle and set IsSelected to true.

<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>

You could also use a Setter instead of a single frame animation but then the selection will be lost again once the focus leaves the ListBox:

<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>
like image 178
H.B. Avatar answered Sep 19 '22 17:09

H.B.


If you have multiple instance of ListBox then you may consider using your custom listbox (by deriving it from ListBox). See the explanation here.


Or, use this hack if you have only 1 (or only small number of) such ListBox and don't want to create a separate class for that:

<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>

Note that you'll have to click once again to edit text in the TextBox (which is actually cool according to me).

like image 27
mg007 Avatar answered Sep 21 '22 17:09

mg007