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
Related
I'm rather new to WPF and XAML, and I'm attempting to create a custom class that extends TextBox, so that I can add some properties for easier validation setup. The validation works fine. The problem is, when I swap out the TextBox in the XAML, the new TextBox updates the border to display an error, but the tool-tip does not show up as expected (see below).
In the picture below, the top 's error tool tip displays correctly, but the 's tool-tip doesn't.
Here's the XAML...
<TextBox x:Name="StrTextBox3" Width="200" Height="50">
<TextBox.Text>
<Binding Path="BinaryIntText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:StrValidationRule ValidatorType="{x:Static validators:StringValidator.BinaryOnly_Validator}"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<validationRules:ValidatedTextBox x:Name="VText" Width="200" Height="50">
<TextBox.Text>
<Binding Path="BinaryIntText2" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:StrValidationRule ValidatorType="{x:Static validators:StringValidator.BinaryOnly_Validator}"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</validationRules:ValidatedTextBox>
And here's the extending class...
class ValidatedTextBox : TextBox
{
public ValidatedTextBox()
{
//
}
}
And the ValidationRule for good measure...
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
return ValidatorType.Validate(Convert.ToString(value)).Match (
Right: result => new ValidationResult(true, null),
Left: error => new ValidationResult(false, error));
}
How do I go about enabling this functionality? Have I not initialized a particular field or two? Am I missing calls to something else? Am I plagued by styles, or some other straight-forward thing that is a quicker fix than doing this write up?
Thank you
Turns out I'm dense; by simply extending the TextBox, the default Style for TextBoxes was not applied, and setting the new Style to an existing TextBox's Style, or just setting in at all, fixed the issue.
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?
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"/>
I have a TextBox with OneWay Mode, so validation does not happen automatically.
<TextBox.Text>
<Binding Path="SelectedValue.Customername"
ElementName="customerListBox"
Mode="OneWay"
>
<Binding.ValidationRules>
<validators:NameValidator ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
I have a button :
<Button Content="Save" Command="{Binding SaveCommand}"/>
Now on ViewModel , I want to validate the Text Input before doing anything else:
SaveCommand = new RelayCommand(
param=>
{
//If validation is true
//Then Execute Res
}
);
Ditch the UI validation rules and have your VM implement IDataErrorInfo and INotifyDataErrorInfo.
Think about it--your save command should not execute unless the data in your VM is valid. That means the validation logic should be in your VM, and not in your UI.
Implementing these interfaces makes it trivial to check whether or not you execute/can execute and fire appropriate events when CanExecute has changed.
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 ?