Does anyone know of a CompareAttribute data annotation for WPF, or a way of achieving the same result in WPF?
For those that don't immediately know, CompareAttribute is a property data annotation for validating in WPF, it takes a string for a second property and returns true if the decorated property and the passed property match.
Basically I need to validate a password change form, to ensure the "retyped password" matches the new password, and do this with data annotations so that i can use the xaml validation template.
You can create your own custom validation logic by creating your own CustomValidationAttribute descrided here.
Try Custom Validator like this
public class EqualsValidationAttribute : ValidationAttribute
{
string propertyToCompare;
public EqualsValidationAttribute(string propertyToCompare)
{
this.propertyToCompare = propertyToCompare;
}
public EqualsValidationAttribute(string propertyToCompare,string errorMessage):this(propertyToCompare)
{
this.ErrorMessage = propertyToCompare;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var propInfo=validationContext.ObjectInstance.GetType().GetProperty(propertyToCompare);
if (propInfo != null)
{
var propValue=propInfo.GetValue(validationContext.ObjectInstance);
if(value!=null && propValue!=null && !string.IsNullOrEmpty(value.ToString()) && !string.IsNullOrEmpty(propValue.ToString()) //if either one is empty dont Validate
&& (value.ToString() != propValue.ToString()))
return new ValidationResult(ErrorMessage);
}
else
throw new NullReferenceException("propertyToCompare must be the name of property to compare");
return ValidationResult.Success;
}
}
and use it in Entity like this
[Required(ErrorMessage="Password Required")]
public string Password {
get { return password; }
set { password = value; RaisePropertyChanged("Password"); }
}
[EqualsValidationAttribute("Password", ErrorMessage = "Confirm password must be same as password")]
public string ConfirmPassword {
get { return confirmedpassword; }
set { confirmedpassword = value; RaisePropertyChanged("ConfirmPassword"); }
}
}
Related
I have a ViewModel in my C# WPF application which contains several properties like this one
public class ExecutionsCreateViewModel : ValidationViewModelBase
{
[Required(ErrorMessage = "Execution name is required.")]
[StringLength(60, ErrorMessage = "Execution name is too long.")]
public string ExecutionName { get; set; }
[...]
}
Thats my ValidationViewModelBase class
public abstract class ValidationViewModelBase : IDataErrorInfo
{
string IDataErrorInfo.Error
{
get
{
throw new NotSupportedException("IDataErrorInfo.Error is not supported.");
}
}
string IDataErrorInfo.this[string propertyName]
{
get
{
if (string.IsNullOrEmpty(propertyName))
{
throw new ArgumentException("Invalid property name", propertyName);
}
string error = string.Empty;
var value = GetValue(propertyName);
var results = new List<ValidationResult>(1);
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = propertyName
},
results);
if (!result)
{
var validationResult = results.First();
error = validationResult.ErrorMessage;
}
return error;
}
}
private object GetValue(string propertyName)
{
PropertyInfo propInfo = GetType().GetProperty(propertyName);
return propInfo.GetValue(this);
}
}
And this is my TextBox in XAML
<TextBox Text="{Binding ExecutionName, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnExceptions=True, ValidatesOnDataErrors=True}"/>
Attributes are working, UI is correctly notified when property becomes invalid ("Invalid" VisualState is triggered).
The problem is, I don't know how to check in Create method if certain property is currently valid or not.
private void Create()
{
if(/*check if property is invalid*/)
{
MessageBox.Show(/*property ErrorMessage*/);
return;
}
//Do something with valid properties
}}
I've tried with Validator.ValidateProperty (1, 2, 3) but it's not working and/or it's too messy. I was also doing tricks like
try
{
ExecutionName = ExecutionName;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
But it's not working in some scenarios and does not look very professional.
Maybe ValidateProperty is the key, but after many "tutorials" I still doesn't know how to fill it to my needs.
Also there is second small thing. Attributes always validate its properties, so when user receive fresh form the ExecutionName will always be null thus Required attribute will mark it as invalid, so that control will automatically turn red. Is there a way to skip validation at initialization?
The problem is, I don't know how to check in Create method if certain property is currently valid or not.
The same way as you do in your ValidationViewModelBase class, e.g.:
private void Create()
{
var value = this.ExecutionName; //the property to validate
var results = new List<ValidationResult>();
var result = Validator.TryValidateProperty(
value,
new ValidationContext(this, null, null)
{
MemberName = "ExecutionName" //the name of the property to validate
},
results);
if (!result)
{
var validationResult = results.First();
MessageBox.Show(validationResult.ErrorMessage);
}
//...
}
For my asp.net MVC View, I used validation annotation and custom validator to verify my fields.
In my ViewModel,
For a test, I used
[StringLength(16, MinimumLength = 8, ErrorMessage = "This is a test to check if validation appears after leaving textbox")]
[Display(Name = "Requestor First Name")]
[Required]
public string RequestorFirstName { get; set; }
In the View, when I type just a letter and leave the textbox focus, the error message appears for stringlength. I know that
client validation is working.
For my custom validator:
[FaceAmount]
public decimal CurrentFaceAmount { get; set; }
When I change the dollar amount in the CurrentFaceAmount field, it does not IMMEDIATELY fire off the custom validation code. Only
after hitting the Submit button, the break point is hit in the following code:
public class FaceAmount : ValidationAttribute, IClientValidatable
{
private string _dependentProperty;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value != null)
{
decimal val;
var isNumeric = decimal.TryParse(value.ToString(), out val);
if (isNumeric)
{
if (val > 0 && val < 100000)
{
return new ValidationResult("Minimum Coverage Amount is $1000.00");
}
}
}
return ValidationResult.Success;
}
}
How can I fire this custom validation code after leaving the textbox focus?
You have to add a client-side validator that looks like this, courtesy of Ode to Code:
jQuery.validator.unobtrusive
.adapters.addSingleVal("greaterdate", "other");
jQuery.validator.addMethod("greaterdate",
function (val, element, other) {
var modelPrefix = element.name.substr(
0, element.name.lastIndexOf(".") + 1)
var otherVal = $("[name=" + modelPrefix + other + "]").val();
if (val && otherVal) {
if (Date.parse(val) <= Date.parse(otherVal)) {
return false;
}
}
return true;
}
);
And link to it using IClientValidatable:
public class DateGreaterThanAttribute :
ValidationAttribute,
IClientValidatable
{
public IEnumerable<ModelClientValidationRule>
GetClientValidationRules(ModelMetadata metadata,
ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationParameters.Add("other", OtherProperty);
rule.ValidationType = "greaterdate";
yield return rule;
}
I have an mvc application with this code:
public class Register
{
[RegularExpression(#"^(?=.*\d)(?=.*[a-zA-Z]).{7,14}$", ErrorMessage = "Password is not in proper format")]
public string Password{ get; set; }
}
What it does is validate the password to contain atleast 7-14 characters, atleast 1 number and 1 upper case letter.
Another requirement is it should not be the same as the email address.
How can I do that? It seems [Compare(Email)] would not be possible on this scenario?
Thanks in advance!
Using MVC Foolproof Validation you can write
[NotEqualTo("EmailAddress", ErrorMessage="Passwords must be different that EmailAddress")]
public string Password{ get; set; }
http://foolproof.codeplex.com/
The easiest way: create your own attribute which inherits CompareAttribute, and override IsValid method. The full code will be like following:
public class NotEqualTo: CompareAttribute
{
public NotEqualTo(string otherProperty) : base(otherProperty)
{
}
protected override System.ComponentModel.DataAnnotations.ValidationResult IsValid(object value,
System.ComponentModel.
DataAnnotations.
ValidationContext
validationContext)
{
PropertyInfo property = validationContext.ObjectType.GetProperty(this.OtherProperty);
if (property == (PropertyInfo) null)
{
return
new ValidationResult(string.Format((IFormatProvider) CultureInfo.CurrentCulture,
"Property {0} does not exist", new object[1]
{
(object) this.OtherProperty
}));
}
else
{
object objB = property.GetValue(validationContext.ObjectInstance, (object[]) null);
if (object.Equals(value, objB))
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
else
return (ValidationResult) null;
}
}
}
i am using asp.net MVC 3 , in my module there are two types of payment modes 1. Wire transfer and 2. PayPal . Now depending on this type 1 and 2 the properties are to be kept Required or other data annotations ! how to do this ?
for eg :
There is a Radio button for payment type ,
If type 1- i.e Wire Transfer is selected then these fields should be validated - First name , last name , email,beneficiary name , bank name , bank no , ifsc code etc
if it is type 2- i.e PayPal then these fields are required - PayPal email .
This could be done by manual validation but is there some way to do it the right way with DataAnnotations?
Simon Ince's blog post seems to be outdated.
There is no need to use DataAnnotationsModelValidator or do a DataAnnotationsModelValidator registration.
You can use the following code:
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable {
private const string _defaultErrorMessage = "'{0}' is required when {1} equals {2}.";
public string DependentProperty { get; set; }
public object TargetValue { get; set; }
public RequiredIfAttribute(string dependentProperty, object targetValue):base(_defaultErrorMessage) {
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}
public override string FormatErrorMessage(string name) {
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, DependentProperty, TargetValue);
}
protected override ValidationResult IsValid(object value, ValidationContext context) {
if (context.ObjectInstance != null) {
Type type = context.ObjectInstance.GetType();
PropertyInfo info = type.GetProperty(DependentProperty);
object dependentValue;
if (info != null) {
dependentValue = info.GetValue(context.ObjectInstance, null);
if (object.Equals(dependentValue, TargetValue)) {
if (string.IsNullOrWhiteSpace(Convert.ToString(value))) {
return new ValidationResult(ErrorMessage);
}
}
}
}
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
ModelClientValidationRule rule = new ModelClientValidationRule();
rule.ErrorMessage = this.FormatErrorMessage(metadata.PropertyName);
rule.ValidationType = "requiredif";
rule.ValidationParameters.Add("depedentproperty", DependentProperty);
rule.ValidationParameters.Add("targetvalue", TargetValue);
yield return rule;
}
}
and the javascript side: if you are using jquery:
$.validator.unobtrusive.adapters.add('requiredif', ['depedentproperty', 'targetvalue'], function (options) {
options.rules["required"] = function (element) {
return $('#' + options.params.depedentproperty).val() == options.params.targetvalue
};
if (options.message) {
options.messages["required"] = options.message;
}
$('#' + options.params.depedentproperty).blur(function () {
$('#' + options.element.name).valid();
});
});
I've updated my example to use MVC 3, so that one is more up to date.
http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx
You could write a custom validator attribute and decorate your model with it:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class CustomValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
var model = value as MyViewModel;
if (model == null)
{
return false;
}
if (model.WireTransfer == 1)
{
return !string.IsNullOrEmpty(model.FirstName) &&
!string.IsNullOrEmpty(model.LastName);
}
else if (model.WireTransfer == 2)
{
return !string.IsNullOrEmpty(model.PaypalEmail);
}
return false;
}
}
and then in your main Model:
[CustomValidation]
public class MyViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
I have used the approach from Simon Ince's blog post and it works well. Basically he creates a RequiredIf data attribute where you can specify the other property and value that must be true in order to make the current field required.
I have two fields in my form
AccountNumber
ReverseAccountNumber
Can i use data annotations to validate that the value of "ReverseAccountNumber" textbox is equal to the reversed value of "AccountNumber".
i.e.
AccountNumber = 12345
ReverseAccountNumber = 54321
i expect the validation to occur on the lostFocus event of the ReverseAccountNumber textbox.
I think i can do this using IDataErrorInfo, However I believe this would require a POST first before validation occurs, and i consider it a last resort.
Simply add a validation attribute to the class (not the properties) and evaluate the class object to compare the two properties. As for the client side, ASP.NET MVC 3 should be able to generate proper client-side validation for this (although I have not tried it myself since Iam still using xVal).
CustomAttribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class ReversStringMatchAttribute : ValidationAttribute
{
public string Property { get; set; }
public ReversStringMatchAttribute()
{ }
public override bool IsValid(object value)
{
return true;
}
}
CustomValidator
public class ReversStringValidator : DataAnnotationsModelValidator<ReversStringMatchAttribute>
{
string property;
public ReversStringValidator(ModelMetadata metadata, ControllerContext context, ReversStringMatchAttribute attribute)
: base(metadata, context, attribute)
{
property = attribute.Property;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule
{
ErrorMessage = Attribute.ErrorMessage,
ValidationType = "reversStringValidator"
};
rule.ValidationParameters.Add("propertyname", property);
return new[] { rule };
}
}
Java Script
Sys.Mvc.ValidatorRegistry.validators["reversStringValidator"] = function (rule) {
//initialization
//return validator function
return function (value, context) {
var field = $get(rule.ValidationParameters['propertyname']);
if (field == null)
return "Property name is invalid!";
var s1 = field.value;
if (s1) {
if (value) {
var reverse = value.split("").reverse().join("");
if (s1 != reverse.toString()) {
return rule.ErrorMessage;
}
} else {
return rule.ErrorMessage;
}
}
return true;
}
};
then use it on your property
public class AccountViewModel
{
[Required(ErrorMessage="Account Number is Required")]
public string AccountNumber { get; set; }
[ReversStringMatch(ErrorMessage = "The value doesn't match the Account Number", Property="AccountNumber")]
public string ReverseAccountNumber { get; set; }
}
i have some doubts on the $get validation method in javascript but it works, for now.