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