Gollum Stripes
Gollum Stripes

Reputation: 65

Set Focus to a textbox under a List DataTemplate

I'm kind of new to WPF and XAML. I made a Listbox with textbox items and I wanted the textbox of the selected item to get focused whenever that item is selected. My friend suggested me to use ItemContainer, and I tried to use a trigger with a setter property of TextBox.IsFocused, but I kept getting an IsFocused cannot be set error.

What went wrong? Below is my code:

Updated the XAML:

<DataTemplate x:Key="Template">
            <Grid Margin="3">
                <Border BorderThickness="2" BorderBrush="Black"
                          Background="{Binding RelativeSource=
                          {
                             RelativeSource 
                             Mode=FindAncestor, 
                             AncestorType={x:Type ListBoxItem}
                          }, 
                          Path=Background
                         }" CornerRadius="4">
                    <StackPanel HorizontalAlignment="Stretch" Margin="3" >
                        <StackPanel.Style>
                            <Style>
                                <Setter Property="TextBlock.Foreground" Value="Black"></Setter>
                            </Style>
                        </StackPanel.Style>
                        <TextBlock Foreground="White" FontSize="18" TextWrapping="Wrap" Text="{Binding Path=BenefitDesc}"></TextBlock>
                        <Grid Margin="3" HorizontalAlignment="Stretch">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="1*" />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <TextBlock Foreground="White" Margin="3" FontSize="16" TextWrapping="Wrap">Price:</TextBlock>
                            <TextBox x:Name="txtUpdate" FontSize="16" Grid.Column="1" TextWrapping="Wrap" Text="{Binding Path=Price}" Margin="3">
                            </TextBox>
                        </Grid>
                    </StackPanel>
                </Border>
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox x:Name="lsItem" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                 HorizontalContentAlignment="Stretch" Background="#FF2CB7D2" SelectionChanged="lsBenPriceEditor_SelectionChanged"
                 ItemTemplate="{StaticResource Template}">
            <ListBox.ItemContainerStyle>
                <Style>
                    <Setter Property="Control.Padding" Value="0"></Setter>
                    <Style.Triggers>
                        <Trigger Property="ListBoxItem.IsSelected" Value="True">
                            <Setter Property="ListBoxItem.Background" Value="DarkRed" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>
    </Grid>

Upvotes: 1

Views: 1662

Answers (1)

Rohit Vats
Rohit Vats

Reputation: 81348

You can hook the SelectionChanged event in your code behind for your Listbox and there you can loop through the visual child of your SelectedItem to find your textBox and simply call textBox.Focus() to put the focus on the textbox.

Code

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
   ListBox lb = sender as ListBox;
   ListBoxItem lbi = (ListBoxItem)lb.ItemContainerGenerator.ContainerFromItem(lb.SelectedItem);
   TextBox textBox = GetVisualChild<TextBox>(lbi);
   if (textBox != null)
      textBox.Focus();
}

private T GetVisualChild<T>(Visual parent) where T : Visual
{
   T child = default(T);
   int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
   for (int i = 0; i < numVisuals; i++)
   {
      Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
      child = v as T;
      if (child == null)
      {
         child = GetVisualChild<T>(v);
      }
      if (child != null)
      {
         break;
      }
   }
   return child;
}

GetVisualChild is generic method which you can use to loop through the VisualChildren for the passed UIControl(ListBoxItem in your case) and return the desired element T(TextBox in your case) from it VisualChildren list.

Moreover, IsFocused property exposed by UIElement is a get only property.

public bool IsFocused { get; }

That's why you are getting this error..

Upvotes: 3

Related Questions