Creating a search box using WPF

15,283

something like:

<StackPanel>
  <TextBox>
    <TextBox.Triggers>
      <EventTrigger RoutedEvent="GotFocus">
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation Duration="0:0:0"
                              Storyboard.TargetName="lb"
                              Storyboard.TargetProperty="(ListBox.Opacity)"
                              To="1" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
      <EventTrigger RoutedEvent="LostFocus">
        <BeginStoryboard>
          <Storyboard>
            <DoubleAnimation Duration="0:0:0"
                              Storyboard.TargetName="lb"
                              Storyboard.TargetProperty="(ListBox.Opacity)"
                              To="0" />
          </Storyboard>
        </BeginStoryboard>
      </EventTrigger>
    </TextBox.Triggers>
  </TextBox>
  <ListBox x:Name="lb"
            Opacity="0">
    <ListBoxItem Content="A" />
    <ListBoxItem Content="B" />
  </ListBox>
</StackPanel>

However in the above approach the ListBox is still holding the space it resides in. if we instead toggle Visibility to Collapsed, every-time the ListBox becomes Visible other control's are going to start moving to accomodate that.

To avoid both these cases, such things are normally implemented via a Popup

<StackPanel>
  <TextBox x:Name="tb" />
  <Popup Width="{Binding RelativeSource={RelativeSource Self},
                          Path=PlacementTarget.ActualWidth}"
          Placement="Bottom"
          PlacementTarget="{Binding ElementName=tb}">
    <Popup.Style>
      <Style TargetType="{x:Type Popup}">
        <Setter Property="IsOpen"
                Value="False" />
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=tb,
                                          Path=IsFocused}"
                        Value="True">
            <Setter Property="IsOpen"
                    Value="True" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Popup.Style>
    <ListBox>
      <ListBoxItem Content="A" />
      <ListBoxItem Content="B" />
    </ListBox>
  </Popup>
</StackPanel>

^^ You'll still see the same output however you no longer have any control's that have to change position due to the popup changing open / close states.

Update:

Download Link

Remember the Trigger is set based on the TextBox having / losing focus. IF you click somewhere that does not take focus, then you will not see the Popup(ListBox) disappear.

Share:
15,283
galbru
Author by

galbru

Updated on June 07, 2022

Comments

  • galbru
    galbru almost 2 years

    I'm trying to create a search box with the controls TextBox and ListBox. When I'm on the TextBox starting to type an event handler GotFocus open the ListBox. I want the ListBox to be closed when the TextBox not on focus. I tried to use the LostFocus event in the TextBox, but it didn't work.

    In which event handler should I use? I didn't find a good example implements this mechanism.

    Edit: I have something like that:

    <Canvas Name="m_MainCanvas" Grid.ColumnSpan="2" >
    <Rectangle MouseDown="Canvas_MouseDown" Fill="White" Height="280" HorizontalAlignment="Left" Margin="256,12,0,0" x:Name="m_MainRectangle" RadiusX="0" RadiusY="0" Stroke="Black" StrokeThickness="3" VerticalAlignment="Top" Width="238" />
    <TextBox Height="23" Margin="10,0,0,210" Name="m_SearchTextBox" VerticalAlignment="Bottom" BorderThickness="0.5" BorderBrush="#69000000" TextChanged="m_SearchTextBox_TextChanged" FontFamily="Kristen ITC" Text="" FontSize="14" FontWeight="Black" HorizontalAlignment="Left" Width="165" Canvas.Top="86" Canvas.Left="274" LostFocus="m_SearchTextBox_LostFocus"/>
    <ListBox  ItemTemplate="{DynamicResource ListBoxItemDataTemplate}" ItemsSource="{Binding}" Name="m_FriendsSearchList" Visibility="Hidden" Background="#FFBCEB85"  Width="181" Height="193"  Canvas.Left="283" Canvas.Top="118">
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClickItemToSelect" />
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
    

    The MouseDown event in the Rectangle control is used to get the TextBox out of focus, but it isn't working.

  • Viv
    Viv almost 11 years
    @Mr.Bean and what does not work for you? Your comment couldn't be any more cryptic. There are "two" approaches mentioned in the answer. If I create a new WPF project in Visual Studio and copy either of the two xaml segments into MainWindow.xaml and run the project they work fine for me.
  • galbru
    galbru almost 11 years
    Your example work, but isn't good for me. The TextBox lost focus only when I click on The ListBoxItem and I'm looking for example of TextBox lost focus when I click in any place outside the TextBox, 'ithout affecting the events of other controls (like Button, i.e if the TextBox is on focus, the ListBox is open, when I click on a button, the TextBox will lost his focus and the click event for the Button will occur.
  • Viv
    Viv almost 11 years
    @Mr.Bean I've added a Download link at the bottom of the post. Get it and try it for yourself. Also read the message I've left below the link. The example has Button's which when clicked will hide the ListBox. If you see the caret blinking in the TextBox when you click elsewhere, it means the Focus is still in the TextBox and you can't expect the ListBox to disappear. ListBox will only disappear when the TextBox loses focus which is what your question stated.