WPF TextBox Validation

Sample problem: set parameter by entering value into a TextBox, check if value is a number in given range, allow clicking a Button if validation was successful.

ValidationRule

ValidationRule is an abstract class from System.Windows.Controls that helps creating custom validation rules for user input.  In this example a derived class DoubleRangeRule will check if user entered a number (double) within a given range (between Max and Min value).

public class DoubleRangeRule : ValidationRule
{
public double Min { get; set; }

public double Max { get; set; }

public override ValidationResult Validate( object value,
CultureInfo cultureInfo )
{
double parameter = 0;

try
{
if( ((string) value).Length > 0 )
{
parameter = Double.Parse( (String) value );
}
}
catch( Exception e )
{
return new ValidationResult( false, "Illegal characters or "
+ e.Message );
}

if( (parameter < this.Min) || (parameter > this.Max) )
{
return new ValidationResult( false,
"Please enter value in the range: "
+ this.Min + " - " + this.Max + "." );
}
return new ValidationResult( true, null );
}
}

 

Validation.ErrorTemplate

Having defined ValidationRule as above if user input is invalid, TextBox will have a red border. Like everything in WPF it is possible to customize it by setting a custom ControlTemplate. My template shows a warning sign and a label explaining error made by user (why input is invalid):

<ControlTemplate x:Key="TextBoxErrorTemplate">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Image Height="16" Margin="0,0,5,0"
Source="Assets/warning_48.png"/>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
/>
</StackPanel>
</ControlTemplate>

Read more about AdornedElement here.

Binding to validation result

On the result of validation can depend many things. For example I would like to bind button IsEnabled property to that deciding to enable button only in user input is valid. Simplest way, in my opinion is to check if TextBox has any validation errors and if no – make button enabled, disabled otherwise. With TextBox called Box (x:Name) binding of Button's IsEnabled property looks like that:

IsEnabled="{Binding ElementName=Box, Path=(Validation.Errors)[0], 
Converter={StaticResource buttonEnabled}}"

 

Final app


Finally we get a TexBbox with validation rules, tips on incorrect input and a Button bound to correctness of input.

<TextBox x:Name="Box" 
Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
<TextBox.Text>
<Binding Path="ValueInBox" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationExpamples:DoubleRangeRule Min="0.5" Max="10"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<Button Content="SaveChanges"
IsEnabled="{Binding ElementName=Box, Path=(Validation.Errors)[0],
Converter={StaticResource buttonEnabled}}"
/>

CorrectValue IncorrectValue

 

If anyone had an idea how to do things like that a better way comments would be much appreciated. VS2008 project here.

Monika

6 Comments

  • Ok, but what if you want to do a more complicated validation, like:

    This option is available if birth data indicates that user is over 18 and is male and country selected is in Europe?

  • Button's IsEnabled property depends here only on one textbox (very simple version). If I had a more complicated problem like you described I would have to think of a more sophisticated bidnig, maybe to an object that represents all this data (age, sex, country) with IsValid property.

    Thanks for the question. I will try to solve the problem and post it later :-)

  • 1. Insetad of TextBox.Text use PasswordBox.Password and done :-)

    2. Bind tooltip's content to error ToolTip={Binding ElementName=Box, Path=(Validation.Errors).CurrentItem}

    MessageBoxes are not very friendly in my opinion, I use them only when errors are severe and I gues you need Messagebox.Show from code behind to show them.

  • Hi,

    What would you do if the window has more than 1 input textboxes button has to be enabled if all the inputs are validated?

    Thanks.

  • Jeriko, try binding each texbox to a property in a class with IsValid method and button to a command with CanExecute method which uses IsValid method from this class. Since many people have been asking I will write a post about it and publish it in an hour or two :-)

  • Monica,

    Thank you for the code.

    Your example does what I want, except, I need to do it all in code. (My WPF window has a varying number of TextBoxes depending on several factors.) So far, I've been baffled by how to set the bindings, paths, updateTriggerSources in code.

    I'd appreciate your naming a place I could look for this or might you re-write the XAML into C#?

    Thanks

Comments have been disabled for this content.