I have the a bunch of textboxes all with data validation as follows:
xaml
<TextBox>
<TextBox.Text>
<Binding Path="Name" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:Validation2/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
c#
public class Validation2 : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
double result;
return double.TryParse(value.ToString(), out result) == true ? new ValidationResult(true, null) : new ValidationResult(false, "error");
}
}
This works nicely, whenever I put anything but a number in the textboxes an error pops up. Now I have a button to send the "form", I'd like the button to check if there were any validation errors before doing anything. How would I go about doing that.
Validation occurs before applying new value to source property. In your case - when you change property. In wpf there are also few more cases, but there is no OnFormClosing or similar. It's by design: control property may be bound to other control property (or several controls bound to same property), so validation occurs at latest when you change focus.
If you don't have cross-bindings, one property is bound to only one control, then you may utilize UpdateSourceTrigger.Explicit - call UpdateSource() for each binding when form is about to be closed.
Other solution would be to don't display errors as popups. Error status could be a red border or ! icon near.
I myself don't use validation mechanism at all. Instead, I have self-validating controls, to example, TextBox with property IsDouble to enable automatic validation for double values and property GetDouble, to parse value. I like more to validate everything at the end, while displaying actual status if validation will be ok or not to the user (red border, flashing caption, etc. per control).
Related
How can I stop the UI layer from performing its conversion validation, or at least have it continue on? If I have a textbox bound to a DateTime:
// view
<TextBox x:Name="StartTimeTextBox">
<TextBox.Text>
<Binding Path="StartTime"
StringFormat="t"
NotifyOnValidationError="True"
ValidatesOnDataErrors="True"
ValidatesOnExceptions="True" >
<Binding.ValidationRules>
<va:AlwaysSucceedsValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
// view model
[MyValidationAttribute]
public DateTime StartTime {get; set;}
When the user selects all the text text in the textbox and deletes it (or types in "asdf"), the conversion fails, it gets a red border and validation stops. I've tried using ValidatesOn... attributes (which I thought would allow my "MyValidationAttribute" to execute) without success. I've also tried adding a ValidationRule that always returns true no matter what the Text - but nothing works.
If you bind TextBox.Text to a DateTime, and the user types in "my hovercraft is full of little lambs", what can the Binding possibly assign to your viewmodel property for you to validate? There's nothing it can do.
You can set Validation.ErrorTemplate for the TextBox to an empty template, and that'll get rid of the red outline business, but you still won't get anything validatable in your viewmodel property.
If you want to validate string input from the user as a valid or invalid date, you're going to have to do that at some point where you have the raw string input in your hands.
If you want to do it in your viewmodel, that means giving your viewmodel a string property for StartTime, and binding that to the TextBox. Call it StringStartTime; in its setter, if the string is valid it sets DateTime StartTime; if not valid, it leaves StartTime alone but sets some error property, or throws an exception, or whatever.
I have a ValidationRules on a textbox;
<TextBox Margin="5,5,5,0" Name="myTextBox" >
<Binding Path="myID" NotifyOnValidationError="True" ValidatesOnDataErrors="True" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<local:ValueCannotBlankValidator ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
Now this works if the user changes the value in the textbox. The problems that it doesn't fire on load. Figured it would be a simple fix of changing UpdateSourceTrigger="PropertyChanged" to UpdateSourceTrigger="LostFocus" but that causes the ValidationRules not to fire. Thanks for the help.
If you set UpdateSourceTrigger="LostFocus", the validation happens when input focus is set to another control, on the other hand, UpdateSourceTrigger="PropertyChanged" fires every time the text is changed, acts much like a TextBox's TextChanged event.
ValidatesOnTargetUpdated="True" ensures that the text is validated on load, your XAML code is correct. If you set a breakpoint in ValueCannotBlankValidator.Validate method you would probably find it is actually fired on load.
I doubt your validator returns a valid result at the first validation, at that moment the Text property of the TextBox is null, if you compare null against string.Empty (""), you get an incorrect result.
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
ValidationResult trueResult = new ValidationResult(true, "not blank");
string str = value as string; //value is null on load, don't compare it against ""
if (string.IsNullOrEmpty(str))
return new ValidationResult(false, "blank");
else
return trueResult;
}
I am having trouble getting a custom ValidationRule to fire, when it is associated with an Expander.Header binding. In fact, the only place I can seem to get these custom rules to fire is in a DataGrid.RowValidationRules block...
The expander is defined in my Window XAML file like so;
<Expander Style="{StaticResource ValidatedSecondLevelExpanderStyle}">
<Expander.Header>
<Binding Path="Name" Mode="OneWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True">
<Binding.ValidationRules>
<ValidationRules:BoundObjectIsValid />
</Binding.ValidationRules>
</Binding>
</Expander.Header>
</Expander>
The bound property 'Name' is displayed correctly, but the validation rule 'BoundObjectIsValid' does not get invoked. Is this possible, and if so, what am I missing?
I know that I could alternately implement IDataErrorInfo on the bound object, however the object can't sensibly validate itself without some context that is provided by other parts of the system. Refactoring is possible, but I'd love to get the ValidationRules to work first!
Refer to the msdn.
The binding engine checks each ValidationRule that is associated with a binding every time it transfers an input value, which is the binding target property value, to the binding source property.
So here in your case, you don't have an inpurt value being transfered to the source property since your Expander.header is not a control which you can use to input values.
Edit: But there is a property named ValidatesOnTargetUpdated' in the ValidationRule. When setting it to true, the validationrule will be applied when the target property is updated
My UI is simple. In a Silverlight 5.0 application, I'm using MVVM and I let the user adds many textboxes as he wants to add in a ObservableCollection<Model> and a Button.
Model just have one property and its datatype is an integer.
The data template for this model is just a simply textbox.
<TextBox Text="{Binding Number}" />
So the idea is, when all the textboxes does not have any error, the command is enabled, but if any model has an error, the command should be disabled.
How can I implement this validation?
Thanks in advance.
You can simply throw an exception in appropriate property`s setter:
public int Number
{
get {//...}
set {
if(value >= 10)
throw new Exception("Number should be less than 10");
_number = number;
}
}
And your binding should be:
<TextBox Text="{Binding Number, Mode="TwoWay" ValidateOnExceptions="True"}" />
FrameworkElement has BindingValidationErrorEvent, which can be used for implement enable/disable command logic. Remember to set NotifyOnValidationError to True for your binding.
p.s.Also, i suggest you read about INotifyDataErrorInfo
I'm making a WPF Application using C#. I want to put validations on integers (0123456789 and ".") only.. The textbox is supposed to contain an IP address... So need to ensure that user key in their correct "IP Address" before they click on the "Submit" button... How can I achieve it?
Thanks.
You can easily implement this using Wpf binding validation rules or by using a custom masked textbox
Check these links for exactly what you are looking for
http://geekswithblogs.net/QuandaryPhase/archive/2008/12/17/wpf-masked-textbox.aspx
http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-validation-rules
Hope it helps..
The following question link on StackOverflow contains a lot of pointers to MaskedTextBox implementation in WPF. You can use it to get IP Address input from user.
Where can I find a free masked TextBox in WPF?
Sounds like you're trying to implement a masked textbox, which is a textbox that auto-format data as the user types according to a specified pattern. Check this tutorial on how to implement this, since is not featured in WPF out-of-the-box: Masked TextBox in WPF
<TextBox IsReadOnly="False" Name="txtIpAddress">
<TextBox.Text>
<Binding Path="IpAddress" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True" >
<Binding.ValidationRules>
<Local:IPValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Public class IPValidationRule: ValidationRule
{
public override ValidationResult Validate(object value,System.Globalization.CultureInfo cultureInfo)
{
if(value == Rejex.Match(your condtion)
{
return new ValidationResult(true, null);
}
else
{
return new ValidationResult(false, "Invalid_Address");
}
}
}