Programmatically change validation rule in WPF TextBox - wpf

I have a text input area defined like this:
<TextBox>
<TextBox.Text>
<Binding Path="MyProperty">
<Binding.ValidationRules>
<valid:MyValidator/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
My problem is that, depending on another setting, what is supposed to be inserted here varies. And thus, the validation behavior of the input data should change.
How can I in the code behind change the active validation rule for a certain textbox?

Use BindingOperations.GetBinding() to get the Binding object for the TextBox.Text. Then manipulate the binding's ValidationRules collection as you see fit.
Binding binding = BindingOperations.GetBinding(myTextBox, TextBox.TextProperty);
binding.ValidationRules.Clear();
binding.ValidationRules.Add(myCrazyValidationRule);

The most hacky solution that comes to mind is to define one textbox for each of the validation rules that should be able to be set. Bind one textbox to each of the validation rules. Then, depending on the external setting/condition, collapse/hide all the textboxes except the one with the validation rule that should be applied.

Related

Insert operations and ValidatesOnDataErrors: controls reported to be invalid as soon as they are displayed

In wpf controls, such as TextBox, you can set ValidatesOnDataErrors=true.
You can also want to change the default value for UpdateSourceTrigger.
For insert operations the textbox initial value is often empty, so its content is supposed to be not valid and it will be rendered with a red border (sure you can override this with styles and templates and obtain what you want). My desired behavior is to validate the content of a control only after the user has changed its content or when he tries to save the data.
It seems to me that the only way to achieve this is to set UpdateSourceTrigger=Explicit, which is not very friendly with pure MVVM.
I have already read the following article, but I'm looking for something simpler.
http://www.shujaat.net/2011/01/updatesourcetrigger-explicit-for-mvvm.html
Thanks
Filippo
Set DataErrorValidationRule like this:
<TextBox>
<TextBox.Text>
<Binding Path="PropertyName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<DataErrorValidationRule ValidatesOnTargetUpdated="False"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

Add ValidationRules into a single xaml line OR shorthand ValidationRules

I'm using a PasswordBox which exposes a dependency property such that I can bind to it. The problem is that by using it like so, I cannot shorthand the Binding.ValidationRules to this syntax:
<PasswordBox services:RPLPasswordBoxBinder.BindPassword="True"
services:RPLPasswordBoxBinder.BoundPassword="{Binding Path=LoginUser.Parola, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</PasswordBox>
I set my ValidationRules to a textbox like this:
<TextBox.Text>
<Binding Path="LoginUser.Parola" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<some validation rule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
Is there any way to specify the ValidationRules collection to my PasswordBox in a single xaml line? Or maybe there's another clever solution for validating user input into my password box?
Some clarifications:
I'm using MVVM and I don't want to use code behind.
I want to add only a single ValidationRule. Maybe the problem with shorthanding Binding.ValidationRules is that this property is a collection. One validationrule would suffice in my situation.
There's a similar question on stackoverflow here. My problem is different as I don't just want to increase readability but actually validate my PasswordBox.
I suggest that you base your data model class on IDataErrorInfo and then validation is performed there and not in the code behind.
There are plenty of examples, but here's one for starters and another here.

wpf validation rules problem with textbox

I created a class IntegersValidationRule which inherits from ValidationRule. Now I don't know what code should I write in XAML. That's what I have:
<TextBox Name="defaultTxt"
Height="23" Width="200">
<TextBox.Text>
<Binding UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<what:IntegersValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
I know that either I'm so stupid that I can't understand in many tutorials what Path in Binding property means, why should we use Binding here when there's no binding required and what should I use instead of 'what' word inside Binding.ValidationRule.
what is an xmlns (see MSDN) which needs to point to the namespace in which your validation rule class is declared, e.g.
xmlns:what="clr-namespace:MyApp.MyValidationRules"
If you add no Path (- how about reading this if you do not understand it? -) the binding will bind to the current DataContext, whatever that may be in your case.
Question 1: validators work on bindings. That is why you specify the rule on a binding. As soon as then value will be updated to the source (object that the control binds to) the rule is checked.
Question 2: See H.B. 's answer

Set of a Property is not being fired when ValidationRule returns false

I have a ValidationRule on a Text Box. When the ValidationResult returns true, this fires the set on the property that the text box is bound to.
When the ValidationResult returns false, the set is not fired.
Any pointers as to why its not firing, and how to solve it, greatly appreciated.
Thanks
Joe
Here is the XAML of the Text Box :
<Binding Path="CorrectEntry" UpdateSourceTrigger="PropertyChanged" NotifyOnValidationError="True" >
<Binding.ValidationRules>
<localValidation:CorrectEntryValidationRule x:Name="validator" ValidatesOnTargetUpdated="True"> <localValidation:CorrectEntryValidationRule.RangeContainer>
<localValidation:CorrectEntryRangeContainer
DataContext="{Binding
Source={StaticResource DataContextBridge},
Path=DataContext}"
Min="{Binding Lower}"
Max="{Binding Upper}"
/>
</localValidation:CorrectEntryValidationRule.RangeContainer>
</localValidation:CorrectEntryValidationRule>
</Binding.ValidationRules>
</Binding>
See the documentation for Validation Rule. it is by design that the property don't get set when Validation Rule returns false.
You should not use Validation Rule, if you want your Propery to be set. You should inherit your class from IDataErrorInfo. And implement the 2 methods from that interface.
This is the normal and usually wanted behavior, if your data is invalid you don't want it to be saved in your model.
(If you want to do validation via exceptions thrown in the setter you can use a property on the binding)

WPF Textbox Binding not Responding when ValidationRule Fired

I have a textbox that has a ValidationRule applied to it:
<TextBox Style="{StaticResource StandardTextBox}"
Grid.Column="1" Grid.Row="4"
IsReadOnly="{Binding SaveModeText}"
MaxLength="50">
<TextBox.Text>
<Binding Path="Individual.SurName"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnDataErrors="True"
ValidatesOnExceptions="True"
NotifyOnValidationError="True">
<Binding.ValidationRules>
<valid:RequiredTextBoxValidationRule
ErrorMessage="Please enter a last name" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
When the page loads the textbox contains the correct value based on its binding. If I delete the value from the textbox the ValidationRule fires properly and I see the error message as expected. My application contains a "Discard Changes" button which reloads the DataContext. The hope was it would reset all of the bindings and once again this textbox would display the original value. For some reason, all other values on the page that do not have a ValidationRule associated with them get reset properly, but this textbox does not.
If I remove the ValidationRule from the XAML the value resets properly. If I handle validation through IDataErrorInfo, the validation fires properly and the value resets properly. Because I have used ValidationRules throughout my application, I was wondering if anyone had come across this issue and resolved it. At this point I would prefer to stick with the implemented ValidationRules if possible, instead of switching everything over to IDataErrorInfo.
Since your you are modifying the value in code, wouldn't you need to have Mode=TwoWay in your binding for it to update? I don't have time to dig in and see if that's what's wrong, but it may be a place to start.

Resources