Stack OverFlow with Custom validator

195 views Asked by At

I have implemented custom validator as following...

 public class RquiredFiledValidation:ValidationRule
{
    public string ErrorMessage { get; set; }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (string.IsNullOrWhiteSpace(value.ToString()))
            return new ValidationResult(false, ErrorMessage);
        else
            return new ValidationResult(true, null);
    }
}

And Attached this with a text box as following...

 <TextBox x:Name="txtLoging" Grid.Column="1" HorizontalAlignment="Stretch" Validation.ErrorTemplate="{x:Null}" VerticalAlignment="Center"  Margin="0,40,30,0">
        <Binding Path="Text" ElementName="txtLoging" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
            <Binding.ValidationRules>
                <Validate:RquiredFiledValidation  ErrorMessage="Please Provide Login Name"></Validate:RquiredFiledValidation>
            </Binding.ValidationRules>
        </Binding>
    </TextBox>

My problem is...

1) When I click directly on login button then the validation doesn't get fired

2) When I put a character in text box validation get fired but produced stack overflow error.

1

There are 1 answers

0
mm8 On BEST ANSWER

I have solve the first problem from code behind as below txtLoging.GetBindingExpression(TextBox.TextProperty).UpdateS‌​ource(); txtPassword.GetBindingExpression(Infrastructure.AttachedProp‌​erty.PasswordAssiste‌​nt.PasswordValue).Up‌​dateSource(); But how solve the same in MVVM

If you care about the MVVM pattern you should not validate your data using validation rules. Validation rules belong to the view and in an MVVM application the validation logic should be implemented in the view model or the model class.

What you should do is implement the INotifyDataErrorInfo interface: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifydataerrorinfo%28v=vs.110%29.aspx

Here is an example for you:

public class ViewModel : INotifyDataErrorInfo
{
    private string _username;
    public string Username
    {
        get { return _username; }
        set
        {
            _username = value;
            ValidateUsername();
        }
    }

    private void ValidateUsername()
    {
        if (_username == "valid")
        {
            if (_validationErrors.ContainsKey("Username"))
                _validationErrors.Remove(nameof(Username));
        }
        else if (!_validationErrors.ContainsKey("Username"))
        {
            _validationErrors.Add("Username", new List<string> { "Invalid username" });
        }

        RaiseErrorsChanged("Username");
    }


    private readonly Dictionary<string, ICollection<string>>
        _validationErrors = new Dictionary<string, ICollection<string>>();

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
    private void RaiseErrorsChanged(string propertyName)
    {
        if (ErrorsChanged != null)
            ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
    }

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName)
            || !_validationErrors.ContainsKey(propertyName))
            return null;

        return _validationErrors[propertyName];
    }

    public bool HasErrors
    {
        get { return _validationErrors.Count > 0; }
    }
}

<TextBox Text="{Binding Username, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />

Please refer to the following blog post for more information about the broad picture of how data validation in WPF works and some comprehensive samples on how to implement it.

Data validation in WPF: https://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/