1

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?

erexo
  • 503
  • 1
  • 6
  • 24
  • *"Is there a way to skip validation at initialization"* - yep, initialize shouldn't validate anything, e.g. by setting back-fields values directly. Properties are fine for UI and user validation, though not your viewmodel nor properties are implementing notifications. – Sinatr Sep 13 '17 at 13:01
  • when I bind a property to XML object attribute, the property is automatically called at initialization becouse that objects attribute seek for initial value for itself. Setting `Mode` to `OneWayToSource` is not helping. When `ValidatesOnDataErrors` is set to true, it check the validation even on initialization – erexo Sep 13 '17 at 13:09

1 Answers1

4

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);
    }

    //...
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • That's the good way to go. I've decided to use `ValidateValue` and catch the exception (if occurs), then the exception Message is an ErrorMessage I need, and this way I don't need `results`. – erexo Sep 13 '17 at 14:04