简体   繁体   中英

WPF/MVVM Validation

Here's the XAML code representing a TextBox used as input for the IdCard

  <TextBox.Text>
     <Binding Mode="TwoWay"
              Path="IdCardNumber"
              UpdateSourceTrigger="PropertyChanged">
                 <Binding.ValidationRules>
                    <v:AlphaNumValidationRule ValidationStep="UpdatedValue" />
                 </Binding.ValidationRules>
     </Binding>
  </TextBox.Text>

The validation :

public class AlphaNumValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (string.IsNullOrWhiteSpace((value ?? "").ToString()))
            return new ValidationResult(false, Resources.Strings.MessagesResource.RequiredField);
        else if (value.ToString().MatchRegex(RegexResource.ALPHANUMERIC))
            return new ValidationResult(true, null);
        else
            return new ValidationResult(false, Resources.Strings.MessagesResource.InvalidFormat);
    }
}

The ViewModel

    public override bool IsValid
    {
        get { return !string.IsNullOrWhiteSpace(IdCardNumber); }
    }
    private string idCardNumber;
    public string IdCardNumber
    {
        get { return idCardNumber; }
        set { Set(() => IdCardNumber, ref idCardNumber, value);
            RaisePropertyChanged("IsValid");
        }
    }

What I want to have is to update IsValid everytime the IdCard input is updated , I tried different ValidationStep but none do as I wish .

At first when loading the input for the first time IsValid is false , when typing a correct value it becomes true after deleting input and adding wrong non-supported values IsValid stays the same since it keeps the last correct value.

Any way to solve this ?

There is an attached event Validation.Error that is fired when binding error occurs.

So basically you could attach to this event and set value of Validation.HasErrors property to your viewmodel's IsValid property.

I see a conflict however. You defined your validation logic in the View, but you want to access it in your ViewModel, that's why you are having troubles.

I recommend you to move entire validation logic to your viewmodel by implementing INotifyDataErrorInfo . then you will have all validation rules and validation errors at your disposal in viewmodel.

You can try to change the UpdateSourceTrigger property with LostFocus :

 <Binding Mode="TwoWay"
          Path="IdCardNumber"
          UpdateSourceTrigger="LostFocus">
             <Binding.ValidationRules>
                <v:AlphaNumValidationRule ValidationStep="UpdatedValue" />
             </Binding.ValidationRules>
 </Binding>

Edit :

To bind the validation result you can use HasError property :

   <TextBox Name="TextBox">
            <TextBox.Text>
                <Binding Mode="TwoWay"
              Path="Text"
              UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:AlphaNumValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
   <TextBlock Text="{Binding (Validation.HasError), ElementName=TextBox}"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM