Click here to Skip to main content
Click here to Skip to main content

Building a Search Text Box Control with WPF

By , 3 Sep 2010
Rate this:
Please Sign up or sign in to vote.

Introduction

I've worked a lot with database applications. Sometimes, providing the capability to search through stored items is a critical requirement. Items may have many fields and, of course, they may be located in different tables. These raise the question of how to design an elegantly effective user interface supporting the capability. I tried some user interface prototypes, but none of them made me feel satisfied. A good solution came up when I used Windows Explorer.

clip_image002

Figure 1: The search text box on the top-right corner of Windows Explorer

The combination of the search button, the text label, and the text box is quite amazing. A lot of space is saved, and the functional design is good. I wanted to use such controls in my applications, but .NET Framework has not provided any standard control like this one. In this article, I'm demonstrating a solution based on WPF. Many thanks fly to David Owens for his wonderful article at http://davidowens.wordpress.com/2009/02/18/wpf-search-text-box/. Technically, his document showed me a practical way to realize my own Search Text Box control which has more functionalities. Now, let's get started!

Designing the control

Figure 2: The control's layout

We're going to create a custom control exposing the following properties:

  • LabelText - When the text box is blank, we'll display this text instead. The default value is "Search".
  • LabelTextColor - The color of the label text. The default will be "Gray".
  • ShowSectionButton - Decides to show the section button or not. This property is very useful if you allow users to search items based on a set of criteria.
  • SectionsList - Holds a list of sections which correspond to the data columns.
  • SectionsStyle - The style of section items. You can choose between CheckBoxStyle, RadioBoxStyle, or NormalStyle.
  • OnSearch - This event is spawn whenever the search button is clicked or the Enter key is pressed.

Here are some images of the control I created:

clip_image006

Figure 3: A sections list styled by CheckBoxStyle

clip_image008

Figure 4: A sections list styled by RadioBoxStyle

clip_image010

Figure 5: List of previous keywords

Creating the layout

The file Generic.xaml contains the XAML code for laying out the control. All that we're doing is modifying the property template.

<ResourceDictionary> <!-- ... -->
  <Style x:Key="{x:Type l:SearchTextBox}" TargetType="{x:Type l:SearchTextBox}">
    <!-- ... -->
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type l:SearchTextBox}">
            <!- XAML code for creating the layout goes here -->
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

Displaying the lists

To customize a standard list box with the above styles, I added another Resource Dictionary file which is named as ListBoxEx.xaml. The file contains definitions of the three styles. We need an adjustment to the way that our lists' items are rendered. For example, if we want our items to have CheckBoxStyle, we simply alter the template ListBoxItem like this:

<Setter Property="ItemContainerStyle">  
<Setter.Value>
        <Style TargetType="{x:Type ListBoxItem}" >
            <Setter Property="Margin" Value="2" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <CheckBox Focusable="False"
                            IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                            RelativeSource={RelativeSource TemplatedParent} }">
                            <ContentPresenter></ContentPresenter>
                        </CheckBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Setter.Value>
</Setter>

With RadioBoxStyle, we must ensure that: at a particular time, there's only one item selected. I don't want to use lengthy C# code to attain this task. Everything seems so easy when every RadioBoxStyle item shares the same Group name:

<Setter Property="ItemContainerStyle">
    <Setter.Value>
        <Style TargetType="{x:Type ListBoxItem}" >
            <Setter Property="Margin" Value="2" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <RadioButton Focusable="False" GroupName="RadioListBoxItems"
                            IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
                            RelativeSource={RelativeSource TemplatedParent} }">
                            <ContentPresenter></ContentPresenter>
                        </RadioButton>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Setter.Value>
</Setter>

So far so good; the remainder is programmatically showing the lists whenever users click on the section button or the previous button.

private Popup m_listPopup = new Popup();private ListBoxEx m_listSection = null;
private ListBoxEx m_listPreviousItem = null;
 
private void BuildPopup()
{
    // initialize the pop up
    m_listPopup.PopupAnimation = PopupAnimation.Fade;
    m_listPopup.Placement = PlacementMode.Relative;
    m_listPopup.PlacementTarget = this;
    m_listPopup.PlacementRectangle = new Rect(0, this.ActualHeight, 30, 30);
    m_listPopup.Width = this.ActualWidth;
    // initialize the sections' list
    if (ShowSectionButton)
    {
        m_listSection = new ListBoxEx((int)m_itemStyle + 
                                  ListBoxEx.ItemStyles.NormalStyle);

        // ...
    }
 
    // initialize the previous items' list
    m_listPreviousItem = new ListBoxEx();
    // ...
}
 
private void HidePopup()
{
    m_listPopup.IsOpen = false;
}
 
private void ShowPopup(UIElement item)
{
    m_listPopup.StaysOpen = true;
    m_listPopup.Child = item;
    m_listPopup.IsOpen = true;
}

private void ChooseSection_MouseDown(object sender, MouseButtonEventArgs e)
{

    if (SectionsList == null)
        return;
    if (SectionsList.Count != 0)
        ShowPopup(m_listSection);
}

private void PreviousItem_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (m_listPreviousItem.Items.Count != 0)
        ShowPopup(m_listPreviousItem);
}

Raising the Search event

Whenever users request to start a new search either by clicking on the search button or entering a keyword, an event OnSearch will be fired. A class named SearchEventArgs provides data for the event.

public class SearchEventArgs: RoutedEventArgs{
    private string m_keyword="";
 
    public string Keyword
    {
        get { return m_keyword; }
        set { m_keyword = value; }
    }
    private List<string> m_sections= new List<string>();
 
    public List<string> Sections
    {
        get { return m_sections; }
        set { m_sections = value; }
    } 
    public SearchEventArgs(): base(){
 
    }
    public SearchEventArgs(RoutedEvent routedEvent): base(routedEvent){
 
    }
}

I've chosen to override the method OnKeyDown to create the event. This is shown below:

protected override void OnKeyDown(KeyEventArgs e) {
    if (e.Key == Key.Escape) {
        this.Text = "";
    }
    else if ((e.Key == Key.Return || e.Key == Key.Enter)) {
        RaiseSearchEvent();
    }
    else {
        base.OnKeyDown(e);
    }
}
 
private void RaiseSearchEvent() {
    if (this.Text == "")
        return;
    if(!m_listPreviousItem.Items.Contains(this.Text))
        m_listPreviousItem.Items.Add(this.Text);
 
 
    SearchEventArgs args = new SearchEventArgs(SearchEvent);
    args.Keyword = this.Text;
    if(m_listSection != null){
        args.Sections = (List<string>)m_listSection.SelectedItems.Cast<string>().ToList();
    }
    RaiseEvent(args);
}

How to use the control

That's it; now the control is ready for action. To use it, you can go through these steps:

  1. Make a reference to the assembly SearchTextBox.dll which contains our control.
  2. Create a namespace in XAML markup like the following in your application XAML namespace:
  3. <Window x:Class="TestUI.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:l="clr-namespace:UIControls;assembly=SearchTextBox"
            Title="Window1" Height="423" Width="487">
  4. Create an instance of the control in the markup:
  5. <l:SearchTextBox Height="39" Margin="118,52,116,0" 
          VerticalAlignment="Top" Name="m_txtTest" Background="AliceBlue" />
  6. Implement the C# code-behind:
    • Create a using directive to use the control in the namespace UIControls.
    • using UIControls;
    • Initialize the control with the appropriate information, for example:
    • public Window1()
      {
          InitializeComponent();
       
          // Supply the control with the list of sections
          List<string> sections = new List<string> {"Author", 
                                     "Title", "Comment"};
          m_txtTest.SectionsList = sections;
       
          // Choose a style for displaying sections
          m_txtTest.SectionsStyle = SearchTextBox.SectionsStyles.RadioBoxStyle;
       
          // Add a routine handling the event OnSearch
          m_txtTest.OnSearch += new RoutedEventHandler(m_txtTest_OnSearch);
      }
       
      void m_txtTest_OnSearch(object sender, RoutedEventArgs e)
      {
          SearchEventArgs searchArgs = e as SearchEventArgs;
       
          // Display search data
          string sections = "\r\nSections(s): ";
          foreach (string section in searchArgs.Sections)
              sections += (section + "; ");
          m_txtSearchContent.Text = "Keyword: " + searchArgs.Keyword + sections;
      }

Conclusion

I hope you liked this article. Any feedback from you is valuable to me for making the control better. Thanks for reading!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Le Duc Anh
Other Bkis
Vietnam Vietnam
I'm a computer freak. Application security, embedded technology and mobile networking are my research fields.
 
I'm now working as a security analyst at Bkis Center, the leading security company in Vietnam.

Comments and Discussions

 
QuestionThe 'x' button isn't user friendly. Pinmemberwa1gon12-Sep-13 7:17 
AnswerRe: The 'x' button isn't user friendly. Pinmemberweaponx729-Jan-14 4:09 
QuestionWhere is the part for binding data for searching to searchbox control? PinmemberDuška Miloradović11-Aug-13 22:42 
AnswerRe: Where is the part for binding data for searching to searchbox control? PinmemberLe Duc Anh11-Aug-13 23:34 
GeneralRe: Where is the part for binding data for searching to searchbox control? [modified] PinmemberDaisy M12-Aug-13 0:42 
GeneralRe: Where is the part for binding data for searching to searchbox control? PinmemberLe Duc Anh12-Aug-13 4:01 
Generalmy vote of 4 PinmemberARIA 52-Dec-12 23:39 
GeneralMy vote of 5 Pinmembernikhil _singh25-Oct-12 2:23 
GeneralRe: My vote of 5 PinmemberLe Duc Anh25-Oct-12 3:08 
Questionneed help for create same control on windows form PinmemberNilesh Makavana12-Aug-12 8:53 
AnswerRe: need help for create same control on windows form PinmemberLe Duc Anh12-Aug-12 16:52 
GeneralRe: need help for create same control on windows form PinmemberNilesh Makavana14-Aug-12 19:33 
i am developing windows application and i need that so.
thank you.
i will try to use it in windows application.
GeneralMy vote of 1 PinmemberMahBulgaria28-Jun-12 4:01 
QuestionClear button is not functioning [modified] PinmemberNikolayKa4-Apr-12 9:32 
AnswerRe: Clear button is not functioning PinmemberLe Duc Anh4-Apr-12 13:45 
AnswerRe: Clear button is not functioning Pinmemberjim19107-Dec-12 11:15 
GeneralRe: Clear button is not functioning PinmemberLe Duc Anh7-Dec-12 13:44 
GeneralRe: Clear button is not functioning Pinmemberjim19107-Dec-12 14:23 
GeneralMy vote of 5 PinmemberDean Oliver1-Feb-12 0:33 
GeneralMy vote of 5 PinmvpKanasz Robert18-Jan-12 21:38 
GeneralMy vote of 5 PinmemberVincenzo Rocco1-Sep-10 11:41 
GeneralRe: My vote of 5 PinmemberLe Duc Anh5-Nov-10 16:52 
GeneralA few recommendations PinmemberPaul B.25-Aug-10 7:01 
GeneralRe: A few recommendations PinmemberLe Duc Anh25-Aug-10 14:58 
GeneralUsing from Silverlight PinmemberAndrusM24-Aug-10 0:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 3 Sep 2010
Article Copyright 2010 by Le Duc Anh
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid