WPF 使用 IDataErrorInfo 验证子 class 属性
WPF Validating a sub-class property with IDataErrorInfo
给定下一个例子:
型号
public class ProjecteModel : ObservableObject, IProjecteModel
{
private string _patientID
public string IdPacient
{
get => _idPacient;
set
{
_idPacient = value;
OnPropertyChanged(nameof(IdPacient));
}
}
/* More fields here... */
}
其中 ObservableObject 是实现 INotifyPropertyChanged 接口的基础 class。
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;
}
}
}
查看
<!-- 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>
验证适用于 CodiClient,但不适用于 IdPacient。
验证方法:public string this[string columnName]
永远不会为 IdPacient 调用。
如何验证子class 属性?
IDataErrorInfo
需要在任何 class 持有您要绑定的 属性 的地方实施。
看看我的 blog post,我的基础可绑定对象 class 实现了 IDataErrorInfo,并包含一个虚拟 ValidatePropety()
方法,该方法从 public string this[string columnName] {}
属性。然后根据需要在每个后代中覆盖 class 以对特定属性执行实际验证。
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 来自 MvvmLight]
给定下一个例子:
型号
public class ProjecteModel : ObservableObject, IProjecteModel
{
private string _patientID
public string IdPacient
{
get => _idPacient;
set
{
_idPacient = value;
OnPropertyChanged(nameof(IdPacient));
}
}
/* More fields here... */
}
其中 ObservableObject 是实现 INotifyPropertyChanged 接口的基础 class。
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;
}
}
}
查看
<!-- 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>
验证适用于 CodiClient,但不适用于 IdPacient。
验证方法:public string this[string columnName]
永远不会为 IdPacient 调用。
如何验证子class 属性?
IDataErrorInfo
需要在任何 class 持有您要绑定的 属性 的地方实施。
看看我的 blog post,我的基础可绑定对象 class 实现了 IDataErrorInfo,并包含一个虚拟 ValidatePropety()
方法,该方法从 public string this[string columnName] {}
属性。然后根据需要在每个后代中覆盖 class 以对特定属性执行实际验证。
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 来自 MvvmLight]