In Prism application I want to using validation.And I have implement the INotifyDataError interface in my ViewModel ,but I found that the validate solution don't be fired when the control is loaded first time.
Then I found the same Question like 'wpf Validation Binding not fired on First Load'
I Found a solution to solve the problem WPF don't fired the validation when first load the datacontext is that:
<TextBox Grid.ColumnSpan="2" Grid.Row="1" x:Name="textBoxFolder" Margin="2,4">
<TextBox.Text>
<Binding Path="this.MovieFolder" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<!-- Validation rule set to run when binding target is updated. -->
<Rules:MandatoryInputRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
as you see,ValidatesOnTargetUpdated="True" is the key point ,this property will make WPF fired the validation when the datacontext load first time.
But I think that's a ugly solution. I need to add a Binding.ValidationRules for every control I want to validate.
Is there a good way to solve the problem.
OK I've solved it: You force the validation when the element got bound with a simple property - ValidatesOnTargetUpdated:
<rules:MyValidationRule ValidatesOnTargetUpdated="True" ValidationType="notnull"/>
Related
I'm using ValidationRules in my xaml forms like this
<TextBox Name="email">
<TextBox.Text>
<Binding Path="email" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:NotEmptyString ValidationStep="RawProposedValue" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
In code, before my transaction begins i check for errors like this
email.GetBindingExpression(TextBox.TextProperty).UpdateSource();
if (Validation.GetHasError(item))
return false;
I have classes that inherit ValidationRule for every validation i need, and this works fine.
But now, i need to call a post method and that method returns me an JSON error when the email already exists, I want to show that error as a validation error. is there a way to set the error to the TextBox?
If you want to stick to this quite unflexible binding validation, then the simplest solution would be to use Binding.ValidatesOnException:
<TextBox Name="email">
<TextBox.Text>
<Binding Path="email"
UpdateSourceTrigger="PropertyChanged"
ValidatesOnException="True">
<Binding.ValidationRules>
<local:NotEmptyString ValidationStep="RawProposedValue" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Then validate your JSON response:
class ViewModel
{
public string Email { get; set; }
private ValidateJsonResponse(Json jsonObject)
{
if (!JsonIsValid(jsonObject))
{
throw new ArgumentException("Email already exists.");
}
}
}
But since exceptions can have some impact on the performance, you generally should avoid them. You can argue, if failed input validation is a good reason to throw an exception. I doubt it is.
Alternatively implement a second ValidationRule and trigger the binding to execute it. You must find a way to access the JSON response to check whether it is valid or not. Since the ValidationRule is instantiated in the XAML and can't have a DependencyProperty to allow binding, this could be slightly complicated. That's why binding validation is not very flexible. The ValidationRule instance of the binding is quite isolated from the rest of the code e.g., the view model.
The recommended pattern is to have your view model implement he INotifyDataErrorInfo interface. See this post for an example or links regarding the implementation: How to add validation to view model properties or how to implement INotifyDataErrorInfo
I got a text box on which I added a validation rule in the xaml. The rule works and it detects errors, but only after the user gives the focus to some other element in the window, like another text box.
This is the defintion:
<TextBox x:Name="textBoxLongitude" Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" VerticalContentAlignment="Center">
<TextBox.Text>
<Binding Path="CustomerLongitude">
<Binding.ValidationRules>
<local:IsDoubleValidationRule MaxValue ="180"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
I've tried solving the issue by adding this to the xaml of the text box:
TextChanged="textBoxTextChanged"
And the implementation:
private void textBoxTextChanged(object sender, TextChangedEventArgs e)
{
CommandManager.InvalidateRequerySuggested();
}
It didn't help..
How can I make the validation rule detect the error and when it's fixed even without the user needing to give the focus to another control?
Set the binding's UpdateSourceTrigger to PropertyChanged to commit and re-evaluate a bound value on every change instead of LostFocus.
Bindings that are TwoWay or OneWayToSource listen for changes in the target property and propagate them back to the source. This is known as updating the source. Usually, these updates happen whenever the target property changes. This is fine for check boxes and other simple controls, but it is usually not appropriate for text fields. Updating after every keystroke can diminish performance and it denies the user the usual opportunity to backspace and fix typing errors before committing to the new value. Therefore, the default UpdateSourceTrigger value of the Text property is LostFocus and not PropertyChanged.
This is how to do it: <Binding Path="CustomerLongitude" UpdateSourceTrigger="PropertyChanged">
I have a textbox that has validation on it, in the validation checks to see if its isNullOrEmpty. The validation works but what I am having difficulty is if the user never selects the textbox and clicks save, I want the validation to run again.
I was able to accomplish this in the XAML.cs file using:
Validation.MarkInvalid(cb.GetBindingExpression(dp), validationError);
Now with MVVM I'm confused how I am able to accomplish this from the viewmodel.
Textbox in question:
<TextBox>
<TextBox.Text>
<Binding Path="LastName">
<Binding.ValidationRules>
<validationRules:IsNullOrEmptyValidationRule/>
</Binding.ValidationRules>
<Binding.UpdateSourceTrigger>PropertyChanged</Binding.UpdateSourceTrigger>
<Binding.Mode>TwoWay</Binding.Mode>
</Binding>
</TextBox.Text>
</TextBox>
Any ideas?
I have a WPF UserControl which allows the editing of an data object (VariableDataGroup). When I use the following syntax the binding works and my user control displays correctly:
<vdi:VariableDataPageView DataContext="{Binding VariableData}" Grid.Row="4" Grid.Column="1" >
Where VariableData is a property on the parent screen's ViewModel.
However, when I try and use the "<Binding>" syntax then my user control doesn't display the data.
<vdi:VariableDataPageView Grid.Row="4" Grid.Column="1" >
<Binding Path="VariableData" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<!--<Binding.ValidationRules>
<validation:VDIComittedValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>-->
</Binding>
</vdi:VariableDataPageView>
The reason I want to switch to using the syntax is to use a custom validation rule to fit in with the exiting code.
First Question: What would be the equivalent syntax to 'DataContext="{Binding VariableData}"' ?
Second Question: Is there a recommended way of performing validation in a UserControl and integrating that with the validation on the parent view? The way I think it should work is that the UserControl performs all its own validation and just passes a validated yes/no result to the parent page but the whole WPF model of programming is new to me.
Thanks,
Canice.
The equivalent syntax to DataContext="{Binding VariableData}"
<vdi:VariableDataPageView Grid.Row="4" Grid.Column="1" >
<vdi:VariableDataPageView.DataContext>
<Binding Path="VariableData" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<!--<Binding.ValidationRules>
<validation:VDIComittedValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>-->
</Binding>
</vdi:VariableDataPageView.DataContext>
</vdi:VariableDataPageView>
A ComboBox.SelectedItemProperty is bound TowWay to a DependencyProperty in
The Control.
In the ControlTemplate :
<ComboBox IsEditable="True">
<ComboBox.SelectedItem>
<Binding RelativeSource="{RelativeSource TemplatedParent}"
Path="SomeDP" Mode="TwoWay" NotifyOnValidationError="True">
<Binding.ValidationRules>
<vld:DeleteAfterInitValidationRule ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</ComboBox.SelectedItem>
</ComboBox>
When the ValidationRule returns false
return ValidationResult(false,msg);
The Dependency Property bound to selected item is not updated.
Is there a way to force the binding to update the source ?
*Please if any one is going to raise a discussion here about
BindingExpression.UpdateSource() , please supply a working example, and not just blurt it out because it sounds like the solution ,
i do not intend to use Explicit mode on my Binding.
Further more i can easily code my way around this but a good .net programmer should thrive to write less code and use the built in mechanisms supplied by the .net framework ,
And that is the soul purpose of this question , is there a built in way of updating the source while
notifying of a DataError ?