Home > database >  WPF Validating a sub-class property with IDataErrorInfo
WPF Validating a sub-class property with IDataErrorInfo

Time:09-23

Given the next example:

Model

public class ProjecteModel : ObservableObject, IProjecteModel
{
    private string _patientID

    public string IdPacient
    {
        get => _idPacient;
        set
        {
            _idPacient = value;
            OnPropertyChanged(nameof(IdPacient));
        }
    }

    /* More fields here... */
}

Where ObservableObject is a base class that implements INotifyPropertyChanged interface.

ViewModel

public class ProjecteViewModel : BaseViewModel, IDataErrorInfo
{
    private IProjecteModel _projecte = new ProjecteModel();
    private string _codiClient;

    public IProjecteModel Projecte
    {
        get => _projecte;
        set
        {
            _projecte = value;
            OnPropertyChanged(nameof(Projecte));
        }
    }

    public string CodiClient
    {
        get => _codiClient;
        set 
        { 
            _codiClient = value;
            OnPropertyChanged(nameof(CodiClient));
        }
    }

    public string this[string columnName]
    {
        get
        {
            string msg = String.Empty;
            switch (columnName)
            {
                case "CodiClient":
                    if (CodiClient.Length <= 0)
                    {
                        msg = "ID Client is required.";
                    }
                    break;

                case "IdPacient":
                //case "Projecte.IdPacient":
                    if (Projecte.IdPacient.Length <= 0)
                    {
                        msg = "Id Pacient is required.";
                    }
                    break;
            };

            return msg;
        }
    }
}

View

    <!-- Id Pacient -->
    <StackPanel Orientation="Vertical" 
                Width="{Binding ElementName=capComandes, Path=ItemsWidth}">
        <TextBlock Text="ID Pacient:" 
                    Style="{StaticResource FieldNameTextBlock}"/>
        <TextBox x:Name="IdPacient"
                    Width="150" 
                    HorizontalAlignment="Left"
                    Margin="0, 0, 0, 15"
                    Foreground="{StaticResource ForegroundFieldValuesBrush}"
                    Text="{Binding Projecte.IdPacient, 
                                   Mode=TwoWay, 
                                   UpdateSourceTrigger=PropertyChanged, 
                                   ValidatesOnDataErrors=True}"/>
    </StackPanel>

    <!-- CodiClient -->
    <StackPanel Orientation="Vertical" 
                Width="{Binding ElementName=capComandes, Path=ItemsWidth}">
        <TextBlock Text="ID Client:" 
                   Style="{StaticResource FieldNameTextBlock}"/>
        <TextBox x:Name="IdClient"
                 Width="150" 
                 HorizontalAlignment="Left"
                 Foreground="{StaticResource ForegroundFieldValuesBrush}"
                 Text="{Binding CodiClient, 
                                Mode=TwoWay, 
                                UpdateSourceTrigger=PropertyChanged, 
                                ValidatesOnDataErrors=True}">
                        </TextBox>
    </StackPanel>

Validation works for CodiClient but it doesn't for IdPacient.

Validation method: public string this[string columnName] is never called for IdPacient.

How can I validate a sub-class property?

CodePudding user response:

IDataErrorInfo needs to be implemented in whatever class holds the property you are binding to.

Take a look at my blog post, where I have my base bindable object class implement IDataErrorInfo, and include a virtual ValidatePropety() method, which is called from the public string this[string columnName] {} property. This is then overridden in each descendent class as required to perform the actual validation on specific properties.

public class perObservableObject: ObservableObject, IDataErrorInfo
{
    private HashSet<string> InvalidProperties { get; } = new HashSet<string>();

    public virtual bool IsValid => !InvalidProperties.Any();

    public bool HasError(string propertyName) => InvalidProperties.Contains(propertyName);

    protected virtual string ValidateProperty(string propertyName) => string.Empty;

    public string this[string columnName]
    {
        get
        {
            if (nameof(IsValid).Equals(columnName))
                return string.Empty;

            var result = ValidateProperty(columnName);

            var errorStateChanged = string.IsNullOrWhiteSpace(result)
                ? InvalidProperties.Remove(columnName)
                : InvalidProperties.Add(columnName);

            if (errorStateChanged)
                RaisePropertyChanged(nameof(IsValid));

            return result;
        }
    }

    // IDataErrorInfo - redundant in WPF
    public string Error => string.Empty;
}

[ObservableObject is from MvvmLight]

  • Related