Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF TextBox with PreviewTextChanged event for filtering

0.00/5 (No votes)
2 Aug 2011 1  
A WPF control, PreviewTextBox, used to filter/validate user input.

Introduction

This article describes the PreviewTextBox control (derived from the standard WPF TextBox control). This control adds a PreviewTextChanged event to allow for simple and flexible validation of user input.

By subscribing to this event, or overriding the OnPreviewTextChanged method, almost any imaginable filtering can be easily implemented. For example, the control could form the basis for a WPF equivalent to the WinForm MaskedTextBox control. However, this exceeded my requirements.

The demo project also provides a sample control, IntTextBox, derived from it. The sample control limits the user to entering valid integral values. The demo project simply displays this sample control to show it in action.

Background

Previously, I wrote an article about a WinForm control that served a similar purpose. I found a need for this control in WPF, but wanted one native to the WPF environment. This article describes the new implementation. Hopefully, others may find it useful.

Many similar articles exist. However, none covered all of the different ways a user might introduce bad data. Most focused solely on user-typed input and paste.

Using the Code

To the end user, PreviewTextBox is nearly identical to the standard WPF TextBox control. It simply adds the PreviewTextChanged event I wish MS had included in their implementation.

To use it in XAML, simply add a namespace to the root element, like so:

xmlns:ex="clr-namespace:Extended.Windows.Controls"

A full-context example of this can be found in the MainWindow.xaml file from the demo project, and looks like this:

<Window x:Class="PreviewText.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ex="clr-namespace:Extended.Windows.Controls"
    Title="Preview Text" Height="100" Width="225">

Once you've done this, you can reference any control in the Extended.Windows.Controls CLR namespace by preceding them with the ex prefix in the XAML. For example:

<ex:IntTextBox Grid.Row="0" Grid.Column="1" Margin="4,0" />

Two approaches to validation are possible. In the first, the end user simply subscribes to the PreviewTextChangedEvent. Setting e.Handled to true in the event handler will cancel the change.

In the second, used in the IntTextBox sample control, the OnPreviewTextChanged method is overridden. By creating a derived control, the same validation can more easily be re-used in XAML.

For those interested in how PreviewTextBox is implemented, the code is fully commented. I will briefly describe the highlights of that implementation in the remainder of this article.

There are three major integration points where native WPF TextBox events are intercepted to raise the PreviewTextChanged event. These include PreviewTextInput, PreviewKeyDown, and PreviewExecutedEvent (from the command manager).

In all cases, the code predicts the resulting text (as if the change had already occurred). This resulting text is provided as a property of the arguments to the PreviewTextChanged event. If the handler sets e.Handled to true in the PreviewTextChanged handler, this same value is communicated to the original event handler.

PreviewTextInput is raised for most of what a user types. It is intercepted by overriding the OnPreviewTextInput method.

PreviewKeyDown is raised when a user presses a key. It is intercepted separately from PreviewTextInput because, for some reason, the space character does not raise that event. It is intercepted by overriding the OnPreviewKeyDown method.

PreviewExecutedCommand is raised for many different editing commands (delete, backspace, etc.) and application commands (Cut, Paste, etc.). It is intercepted by adding a handler in the overridden OnInitialized method. The handler is added as follows:

AddHandler(CommandManager.PreviewExecutedEvent,
  new ExecutedRoutedEventHandler(previewExecutedEvent), true);

This results in the previewExecutedEvent method being invoked each time the user initiates one of these commands for the PreviewTextBox control.

Points of Interest

The code does not currently intercept programmatic assignments to the Text property. I was unable to reliably intercept such changes. Also, they were not necessary for filtering user input.

The code does not, by default, intercept the application commands Undo and Redo. The mechanism for intercepting these commands is rather messy. Because the undo stack is not available, it requires an undo and redo (or the reverse) simply to predict the text that would result. A property PreviewUndoEnabled is provided to enable this optional logic. However, with proper validation elsewhere, neither Undo or Redo can introduce invalid values.

History

  • 8/1/2011 - The original version was uploaded.

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