Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / Windows Forms
Article

A User-Searchable TextBox, RichTextBox, ListView, and TreeView in C#

Rate me:
Please Sign up or sign in to vote.
4.79/5 (58 votes)
18 Aug 20066 min read 285.5K   4.5K   176   61
A lightweight class library that extends the Framework's most popular editor controls to include search and other basic functionality.

Example application screenshot

Introduction

When using an application that presents a lot of text in controls, users will expect to be able to search for text phrases by pressing Ctrl-F. Unfortunately for the application developer, while adding the control is just a matter of dragging it from the toolbox, adding the search functionality is a bit more work.

To solve this, I developed a lightweight class library, SearchableControls, that contains ready-to-use SeachableTextBox, SearchableRichTextBox, SearchableListView, and SearchableTreeView controls. These are straight extensions of the Framework classes, and so they behave identically, other than the user's ability to search them with Ctrl-F or the context menu, and some other basic enhancements. In the case of the text box controls, users can also search and replace text using the standard Ctrl-H shortcut. These options are also available from the context menu.

Find features

The search dialog is designed to behave like standard Windows applications such as Notepad. Features include;

  • After the first result is returned, the user can continue to search ("search again") from the search dialog.
  • The text entry box is a combo box featuring a history of previous searches.
  • Either a case-sensitive or case-insensitive search can be selected.
  • The user can select to use wildcards (* or ?) or full regular expressions in the search.
  • Searches will continue from the top of the document until the original search position is reached.
  • If the user moves or resizes the search dialog control, its position will be restored if the search dialog is displayed again on that particular searchable control.
  • For text boxes, the word under the caret when the user selects search is the default search term.

Additional features

Example of replace dialog

The main feature of these controls is the search function. However, I have also added some functionality conspicuously absent from the basic controls.

For SearchableRichTextBox, this includes a full context (right click) menu (including Copy, Paste, etc.). The basic RichTextBox does not supply a context menu. The same is supplied for the SearchableTextBox. (This is useful because you cannot supplement or override TextBox's context menu - only replace it completely.)

Also available is a FindDialog toolbox control which allows developers to add search functionality to their own controls. Other than a drag and drop, it is only necessary to supply a SearchRequested event handler and the shortcut code.

The enhanced context menu

SearchableRichTextBox also includes the ability to format text from the context menu or keyboard (Ctrl-B toggles bold, Ctrl-I toggles italics, and Ctrl-U toggles underlining). A dialog to change the font of the selected text is also on the context menu.

I have also added a shortcut key for Ctrl-A to select all the text in the controls (other than the extension of TreeView, which famously does not support multiple selection). This is another feature surprisingly absent from the Framework implementations.

Using the code

Getting the controls into the toolbox

From the DLL:

The controls can be used directly from the binary library (SearchableControls.dll). In Visual Studio 2005, right click on the form designer toolbox, and select Choose Items. Then click the Browse button, and navigate to and open the .dll. Click OK, and the four controls will now be added somewhere to the toolbar.

From the source:

Download the source, and add the SearchableControls.vcproj to your solution. Build the solution, and the controls should appear in your toolbox automatically. If this doesn't happen, closing and re-opening Visual Studio can encourage it.

The controls in the toolbox

Getting the controls into your form

This is a matter of dragging them to your form from the designer toolbox in the usual way. Build and run your application, click on the new control, press Ctrl-F, or right click->Find, and you will see the Find dialog. Typing the text and pressing Return or clicking the Search button will search the contents of the control. Pressing F3 in the Find dialog or in the control will search for the next occurrence of the string. Once the remainder of the document has been searched, searches will take place from the start of the document.

The find dialog

Adding the Find entries to the parent form menu

Users will expect to see Find under the form's Edit menu. In the designer, add the Edit->Find menu item to your form and give it a Click event. Add a call to SearchableControls.OpenFindDialog(Controls); as below...

C#
private void findToolStripMenuItem_Click(object sender, EventArgs e)
{
    SearchableControls.Utility.OpenFindDialog(Controls);
}

Now, add an Edit->Find Again menu item, and give it a Click event. Add a call to SearchableControls.Utility.FindNext(Controls); as below ..

C#
private void findAgainToolStripMenuItem_Click(object sender, EventArgs e)
{
    SearchableControls.Utility.FindNext(Controls);
}

These functions allow multiple searchable controls on a form as they will select the most appropriate based on focus. However, all controls apply the interface ISearchable. This exposes a single function FindDialog() which returns the FindDialog object associated with that control. Calling Show() on this object will present the Find dialog to the user. Other functionality is available, see the source code or metadata for more details. This allows an individual control's Find functionality to be controlled externally by menus, toolboxes, or whatever.

How it works

Each control supplies KeyDown events and context menu items to control its own FindDialog object. This object raises events such as SearchRequested and ReplaceRequested to control the actual search behaviour on the parent form. The parent control searches its text with a supplied regular expression, and uses its normal selection method to highlight any found text.

A note about HideSelection

Most Framework controls have a HideSelection property which controls if selections are visible when the control is not focused. As selection is used to indicate search results which should be visible when the Find dialog is focused, it is necessary to turn off HideSelection temporarily, or search results will be invisible.

Unfortunately, a slight flicker is visible when this property is altered. One way to stop that is to set HideSelection to false permanently on individual controls, using the designer. This is usually acceptable if there is only one major control on the form.

Customizing the library

Customizing the Find dialog

It is a simple matter for developers to customize the appearance of the Find dialog using Visual Studio's designer. Unwanted controls can simply be hidden from the view.

Extending other controls to be searchable

Drag a FindDialog object from the toolbox to your chosen control. Supply a SearchRequested event handler.

This event handler has a minimum function it is required to perform. It is expected to search its content from after the current selection until the end, and then from the top of the content until the current selection. It is expected to match text against the regular expression supplied in e.SearchRegularExpression, e.g., e.SearchRegularExpression.IsMatch(myText), select any found content, and return 'true'. If no matches are found, it is expected to return 'false'.

Using regular expressions frees the controls from having to process case sensitivity and other exotic search options such as wildcards.

As mentioned above, if you are deriving from a Framework control, and using selection to indicate search results, you will probably need to turn off HideSelection. This can either be done permanently, or when selections are actually made, as with the SearchableControl controls.

Further development

The idea of supplying the expected basic functionality to controls could be explored further.

History

  • 08 July 2006 :- Initial release.
  • 08 Aug 2006 :- Version 1.2 release, including replace functionality, search history, and FindDialog as a toolbox control.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United Kingdom United Kingdom
Jim Blackler has been a programmer in the games industry for over 10 years. Based in Surrey, UK.

Comments and Discussions

 
QuestionLicense info Pin
aks47317-Mar-16 23:03
aks47317-Mar-16 23:03 
QuestionSorry For this Question Pin
ahamedgad16-Nov-13 10:04
ahamedgad16-Nov-13 10:04 
QuestionHow to Use with Krypton Controls Pin
Andrew Schultz24-Jul-12 2:53
Andrew Schultz24-Jul-12 2:53 
AnswerRe: How to Use with Krypton Controls Pin
Andrew Schultz24-Jul-12 4:19
Andrew Schultz24-Jul-12 4:19 
Questionopen from menu Pin
mmsalman874-Jul-12 22:53
mmsalman874-Jul-12 22:53 
QuestionThanks Jim, Love the code, I made an addition... Pin
TheMattster25-May-12 10:17
TheMattster25-May-12 10:17 
QuestionWorked Perfectly Pin
Member 86976879-May-12 11:02
Member 86976879-May-12 11:02 
GeneralMy vote of 5 Pin
farshidmaj2-Jun-11 5:45
farshidmaj2-Jun-11 5:45 
GeneralfindForm_Closing , focus problem Pin
atillatan4-Nov-09 8:55
atillatan4-Nov-09 8:55 
GeneralExtender Provider Pin
D-2-D12-Jul-09 7:49
D-2-D12-Jul-09 7:49 
QuestionHow can I set cursor position to the position of the found search item Pin
Georg Schmitz12-Jun-09 23:16
Georg Schmitz12-Jun-09 23:16 
Jokegood job Pin
fllsm19-Mar-09 20:11
fllsm19-Mar-09 20:11 
GeneralWonderful! Pin
Kenny McKee11-Mar-09 14:45
Kenny McKee11-Mar-09 14:45 
GeneralNot able to download this Source code zip file Pin
naveen.gundu5-Nov-08 23:02
naveen.gundu5-Nov-08 23:02 
Questionhow to sort in listview help me Pin
katou kid9-Oct-08 22:18
katou kid9-Oct-08 22:18 
GeneralFindSearchable not working for container controls Pin
AndrusM28-May-08 23:01
AndrusM28-May-08 23:01 
GeneralRe: FindSearchable not working for container controls Pin
Jim Blackler28-May-08 23:54
Jim Blackler28-May-08 23:54 
GeneralRe: FindSearchable not working for container controls Pin
AndrusM29-May-08 1:41
AndrusM29-May-08 1:41 
NewsBUG - Regex and Wildcard match logic is swapped! Pin
Ross Korsky6-Mar-08 9:26
Ross Korsky6-Mar-08 9:26 
GeneralRe: BUG - Regex and Wildcard match logic is swapped! Pin
Jim Blackler6-Mar-08 10:11
Jim Blackler6-Mar-08 10:11 
GeneralThank you Pin
vdfr123417-Nov-07 12:45
vdfr123417-Nov-07 12:45 
GeneralThanks a lot Pin
Emil15003-Sep-07 0:27
Emil15003-Sep-07 0:27 
QuestionVery good job... Pin
3think22-Aug-07 10:47
3think22-Aug-07 10:47 
AnswerRe: Very good job... Pin
Jim Blackler22-Aug-07 11:50
Jim Blackler22-Aug-07 11:50 
If by menu you mean the right click context menu, this ought to work in C#:

Add this function in a somewhere in your code (a good place would be the form hosting the control you want to customize).

/// <summary>
/// General purpose function to merge context menus
/// </summary>
/// <remarks>Used to allow an inheriting control to add items to the
/// parent context menu without replacing it completely.</remarks>
public static void MergeContextMenus(ContextMenuStrip target, ContextMenuStrip source)
{
    List<ToolStripItem> list = new List<ToolStripItem>();

    foreach (ToolStripItem item in source.Items)
    {
        list.Add(item);
    }

    foreach (ToolStripItem item in list)
    {
        target.Items.Add(item);
    }
}


(For List<> don't forget the "using System.Collections.Generic;" at the top of wherever you add it.)

In the form with the control on it, add a ContextMenu in the designer containing the items you want to add.

In the form's constructor, after InitializeComponent();, add this line (I assume the menu you added is called contextMenuStrip1. I assume your control is called searchableListView1) ...

MergeContextMenus(searchableListView1.ContextMenuStrip, contextMenuStrip1);

Hope that works.

Jim
QuestionRe: Very good job... [modified] Pin
3think23-Aug-07 9:29
3think23-Aug-07 9:29 

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

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