Table data verification is often boring and unavoidable.
If the following form has only two input boxes and a confirmation button, what do we need to do normally?
1. If a non-numeric string is entered in the age input box and the input box loses focus, the following error message should be immediately prompted.
2. If the content of the error message changes, you may need to modify the overall uidesign (for example, it is displayed below the input box)
3. Click the OK button to traverse all input boxes in the Window. If any input data does not match the verification result, an error is prompted and the corresponding control gets the focus.
Is this easy? What if there are more input boxes?
The following Demo shows how WPF can easily handle these issues:
In the Window, textBox1, textBox2, and textBox3 are bound to the following data:
DataSource public class MyDataSource { private int _age; private int _age2; private int _age3; public MyDataSource() { Age = 0; Age2 = 0; } public int Age { get { return _age; } set { _age = value; } } public int Age2 { get { return _age2; } set { _age2 = value; } } public int Age3 { get { return _age3; } set { _age3 = value; } } }
- Use custom verification rules
<TextBox Name="textBox1" Width="50" FontSize="15" Validation.ErrorTemplate="{StaticResource validationTemplate}" Style="{StaticResource textBoxInError}" Grid.Row="1" Grid.Column="1" Margin="2"> <TextBox.Text> <Binding Path="Age" Source="{StaticResource ods}" UpdateSourceTrigger="PropertyChanged" > <Binding.ValidationRules> <c:AgeRangeRule Min="21" Max="130"/> </Binding.ValidationRules> </Binding> </TextBox.Text></TextBox>
TextBox1 is bound with Age and uses the verification rule AgeRangeRule. The minimum and maximum values are specified in the rule. When PropertyChanged, the verification rule is triggered, that is, when the control loses focus. the prompt information style is defined in ErrorTemplate. Let's take a look at ErrroTemplate content:
<ControlTemplate x:Key="validationTemplate"> <DockPanel> <TextBlock Foreground="Red" FontSize="20">!</TextBlock> <AdornedElementPlaceholder/> </DockPanel> </ControlTemplate>
AdornedElementPlaceholder is the focus here, where the control to be verified is placed, and the entire ErrorTemplate uses the magic Adoner to achieve the error prompt location and the original layout is irrelevant. the verification rules are completely decoupled from the entire code:
rule public class AgeRangeRule : ValidationRule { private int _min; private int _max; public AgeRangeRule() { } public int Min { get { return _min; } set { _min = value; } } public int Max { get { return _max; } set { _max = value; } } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { int age = 0; try { if (((string)value).Length > 0) age = Int32.Parse((String)value); } catch (Exception e) { return new ValidationResult(false, "Illegal characters or " + e.Message); } if ((age < Min) || (age > Max)) { return new ValidationResult(false, "Please enter an age in the range: " + Min + " - " + Max + "."); } else { return new ValidationResult(true, null); } } }
The exception thrown when the verification rule fails is displayed in the Tip.
<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/> </Trigger> </Style.Triggers> </Style>
- Use predictionvalidationrule
Another method, such:
<TextBox Name="textBox3" Width="50" FontSize="15" Grid.Row="5" Grid.Column="1" Margin="2" Validation.ErrorTemplate="{StaticResource validationTemplate}" Style="{StaticResource textBoxInError}"> <TextBox.Text> <Binding Path="Age3" Source="{StaticResource ods}" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox>
In the background code:
BindingExpression myBindingExpression = textBox3.GetBindingExpression(TextBox.TextProperty); Binding myBinding = myBindingExpression.ParentBinding; myBinding.UpdateSourceExceptionFilter = new UpdateSourceExceptionFilterCallback(ReturnExceptionHandler); myBindingExpression.UpdateSource();
Because Age3 is of the Int type, inputting a non-int type in textBox3 will cause an exception. In this case, the system uses the Rule ExceptionValidationRule, and the module with the same error information remains unchanged.
- Verify all controls
// Validate all dependency objects in a window bool IsValid(DependencyObject node) { // Check if dependency object was passed if (node != null) { // Check if dependency object is valid. // NOTE: Validation.GetHasError works for controls that have validation rules attached bool isValid = !Validation.GetHasError(node); if (!isValid) { // If the dependency object is invalid, and it can receive the focus, // set the focus if (node is IInputElement) Keyboard.Focus((IInputElement)node); return false; } } // If this dependency object is valid, check all child dependency objects foreach (object subnode in LogicalTreeHelper.GetChildren(node)) { if (subnode is DependencyObject) { // If a child dependency object is invalid, return false immediately, // otherwise keep checking if (IsValid((DependencyObject)subnode) == false) return false; } } // All dependency objects are valid return true; }
Click confirm to use this method for verification again. If the data is invalid, the user cannot submit
Code: Download