WPF ValidationRules does not fire on load - c#

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;
}

Related

WPF TextBox Error Message Visible and Doesn't Disappears When Text Written in TextBox

Error Message already showing when I build and run the code in TextBox and doesn't disappear when text is written in TextBox
I am using Visual Studio Community Edition 2017
I am using MaterialDesignThemes Version 2.6.0
I have used the TextBox code form the DemoApp
<TextBox
x:Name="NameTextBox"
materialDesign:HintAssist.Hint="Name"
VerticalAlignment="Top"
HorizontalAlignment="Center"
Width="200">
<TextBox.Text>
<Binding
Path="Name"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<rules:NotEmptyValidationRule
ValidatesOnTargetUpdated="True"
xmlns:rules="clr-namespace:Spirit.Domain" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
This is My NotEmptyValidationRule defined in Spirit.Domain namespace which is a copy of validation rules form the demo app
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
return string.IsNullOrWhiteSpace((value ?? "").ToString())
? new ValidationResult(false, "Field is required.")
: ValidationResult.ValidResult;
}
I have also included a gif
Please provide a demo or details steps for solving the error
Just needed to add PropertyChanged event on the Name property used in the binding..

Doing all my validation in the ViewModel

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.

WPF validation without updating the data source

I have a TextBox displaying the time part of a DateTime:
<TextBox HorizontalAlignment="Left" Height="23" Margin="0,13,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Validation.Error="Validation_OnError">
<TextBox.Text>
<Binding Path="MyDate" StringFormat="HH:mm" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<c:TimeValidator></c:TimeValidator>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Is it possible to do the validation on property change, and the conversion on lost focus?
I want to have the validation on property changed, but I want to have my data source updated on lost focus. Otherwise, the converter will kick in while the user is editing in the TextBox. This might be a problem if the values is 10:50 and the user deletes the last number, so that the value becomes 10:5. The converter will then convert this to 10:50. This is okay to do on lost focus, but not on property changed. But for the sake of the validator, i want to validate on property change so the user have the red border as long as the entered value is not valid.
Yes! I was just wrestling with this. AFAIK, there is no XAML combination for this--it must be done in the codebehind, and you need a direct reference to the element.
Element.GetBindingExpression(PropertyName).ValidateWithoutUpdate();
You'll probably want to check that GetBindingExpression doesn't return null; this will run any converters you have attached (presumably to supply the converted value to converters with ValidationStep set to ConvertedProposedValue), but will not update the source. And, of course, you'll have to call this in some event, perhaps TextChanged or somesuch. Here is the MSDN documentation for it: https://msdn.microsoft.com/en-us/library/system.windows.data.bindingexpressionbase.validatewithoutupdate(v=vs.110).aspx
Use this code:
BindingExpression expression =
txtStudentName.GetBindingExpression(TextBox.TextProperty);
expression.ValidateWithoutUpdate();
If you want to update it's source after check use this code:
BindingExpression expression =
txtStudentName.GetBindingExpression(TextBox.TextProperty);
expression.ValidateWithoutUpdate();
if (expression!=null && !expression.HasError)
expression.UpdateSource();

How to check ValidationResults on button click

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

TextBox UpdateSourceTrigger for PropertyChanged and LostFocus

Hello I have question about a wpf/xaml text box c# implementation.
I am trying to figure out how in my c# code to know what the UpdateSourceTrigger is being used.
I am a newbie, so I would very much appreciate if people are patient with me and helpful.
In my C# I need to know how the data in the Text box is trying to be accessed using UpdateSourceTrigger. I know the property changed when my OnPropertyChanged() is called. But I also need to know how if the user is trying to use LostFocus or PropertyChanged in the C# code. This is so I can do some special processing for either case.
xaml
<TextBox>
<TextBox.Text>
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
c#
protected void OnPropertyChanged(string name)
{
// If UpdateSourceTrigger= PropetyChanged then process one way
// If UpdateSourceTrigger= LostFocus then process one way
}
Is there any other methods that get called when using LostFocus?
Thanks you
You will have to get a reference to your TextBlock and get the binding expression then you will have access to the Binding information
Example:(no error/null checking)
<TextBox x:Name="myTextblock">
<TextBox.Text>
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
var textblock = this.FindName("myTextBlock") as TextBlock;
var trigger = textblock.GetBindingExpression(TextBlock.TextProperty).ParentBinding.UpdateSourceTrigger;
// returns "PropertyChanged"
another way of getting the binding object is:
Binding binding = BindingOperations.GetBinding(myTextBox, TextBox.TextProperty);
if (binding.UpdateSourceTrigger.ToString().Equals("LostFocus"))
{
}
else
{
}

Categories

Resources