如何使用 INotifyDataErrorInfo 接口验证 Observable 集合
How to validate Observable Collection with INotifyDataErrorInfo interface
我正在使用 MVVM
模式开发 WPF
应用程序并使用 Prism
框架。
我有一个基本数据class如下。
public class ProductDecorator : DecoratorBase<Product>
{
private string _ProductShortName;
private Boolean _IsSelected = false;
// I have omitted some code for clarity here.
[Required]
public int ProductID
{
get { return BusinessEntity.ProductID; }
set
{
SetProperty(() => BusinessEntity.ProductID == value,
() => BusinessEntity.ProductID = value);
}
}
public Boolean IsSelected
{
get { return _IsSelected; }
set
{
SetProperty(ref _IsSelected, value);
}
}
}
我在 ViewModel 中创建了上述数据的可观察集合 class。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
}
并且我将这个可观察的集合限制在视图中的列表框中。
<telerik:RadListBox ItemsSource="{Binding ProductDecorators}" HorizontalAlignment="Stretch" Margin="5,10,5,5" Grid.Column="1" VerticalAlignment="Top">
<telerik:RadListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="2" IsChecked="{Binding IsSelected}" />
<TextBlock Text="{Binding ProductShortName}" FontSize="14" />
</StackPanel>
</DataTemplate>
</telerik:RadListBox.ItemTemplate>
</telerik:RadListBox>
根据以上内容,我想验证一下"the user must select at least one item in the list box"。换句话说,IsSelected
属性 在 可观察集合的 ProductUmDecorator
class 之一中必须是 true ProductUmDecorators
.
目前我使用 INotifyDataErrorInfo
接口和 Data Annotations
验证规则。我忘记了 我应该如何实施我的问题来实现此验证?
Whosebug 上有很多与此主题相关的问题,但没有可靠的答案。所以我决定 post 我的解决方案作为这个问题的答案。
问题的上下文是检查“用户必须select列表框中的一项与可观察集合绑定”。
第一步,ObservableCollection
中的项目(实体)需要IsSelected
属性。
public class ProductDecorator : DecoratorBase<Product>
{
private string _ProductShortName;
private Boolean _IsSelected = false;
// I have omitted some code for clarity here.
public Boolean IsSelected
{
get { return _IsSelected; }
set
{
SetProperty(ref _IsSelected, value);
}
}
}
第二步,ObservableCollection
中的每一项都必须实现INotifyPropertyChanged
接口。然后你可以访问 PropertyChanged
事件处理程序。
第三步,您需要将以下方法附加到ObservableCollection
的CollectionChanged
事件处理程序。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
public SaleInvoiceViewModel() {
_productDecorators= new ObservableCollection<ProductDecorator>();
_productDecorators.CollectionChanged += ContentCollectionChanged;
}
public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach(ProductDecorator item in e.OldItems)
{
//Removed items
item.PropertyChanged -= EntityPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach(ProductDecorator item in e.NewItems)
{
//Added items
item.PropertyChanged += EntityPropertyChanged;
}
}
}
}
仔细看上面代码中的EntityPropertyChanged
方法。只要 ObservableCollection
中任何项目的任何属性发生更改,就会触发此方法。然后,你可以简单地在EntityPropertyChanged
方法中调用Validate
方法。
private void EntityPropertyChanged( object sender, PropertyChangedEventArgs e )
{
if (e.PropertyName == "IsSelected")
this.Product.ValidateProperty("ProductUmDecorators");
}
如果更改后的 属性 为 IsSelected
,则 ValidatedProperty
方法将为 运行。
我将省略 ValidateProperty
方法的详细实现。此方法将尝试使用 DataAnnotations
验证 属性 并在出现任何错误时触发 ErrorChanged 事件。可以详细了解here.
最后,您需要在 Entity/ViewModel/Decorator class 中实现自定义 DataAnnotation
ValidationAttribute
,其中您的 ObservableCollection
属性 如下所示代码。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
[AtLeastChooseOneItem(ErrorMessage = "Choose at least one item in the following list.")]
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
}
public class AtLeastChooseOneItem : ValidationAttribute
{
protected override ValidationResult IsValid( object value, ValidationContext validationContext )
{
ProductDecorator tmpEntity = (ProductDecorator) validationContext.ObjectInstance;
var tmpCollection = (ObservableCollection<ProductUmDecorator>) value;
if ( tmpCollection.Count == 0 )
return ValidationResult.Success;
foreach ( var item in tmpCollection )
{
if ( item.IsSelected == true )
return ValidationResult.Success;
}
return new ValidationResult( ErrorMessage );
}
}
这是一个有点复杂的解决方案,但这是迄今为止我找到的最可靠的解决方案。
我正在使用 MVVM
模式开发 WPF
应用程序并使用 Prism
框架。
我有一个基本数据class如下。
public class ProductDecorator : DecoratorBase<Product>
{
private string _ProductShortName;
private Boolean _IsSelected = false;
// I have omitted some code for clarity here.
[Required]
public int ProductID
{
get { return BusinessEntity.ProductID; }
set
{
SetProperty(() => BusinessEntity.ProductID == value,
() => BusinessEntity.ProductID = value);
}
}
public Boolean IsSelected
{
get { return _IsSelected; }
set
{
SetProperty(ref _IsSelected, value);
}
}
}
我在 ViewModel 中创建了上述数据的可观察集合 class。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
}
并且我将这个可观察的集合限制在视图中的列表框中。
<telerik:RadListBox ItemsSource="{Binding ProductDecorators}" HorizontalAlignment="Stretch" Margin="5,10,5,5" Grid.Column="1" VerticalAlignment="Top">
<telerik:RadListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="2" IsChecked="{Binding IsSelected}" />
<TextBlock Text="{Binding ProductShortName}" FontSize="14" />
</StackPanel>
</DataTemplate>
</telerik:RadListBox.ItemTemplate>
</telerik:RadListBox>
根据以上内容,我想验证一下"the user must select at least one item in the list box"。换句话说,IsSelected
属性 在 可观察集合的 ProductUmDecorator
class 之一中必须是 true ProductUmDecorators
.
目前我使用 INotifyDataErrorInfo
接口和 Data Annotations
验证规则。我忘记了 我应该如何实施我的问题来实现此验证?
Whosebug 上有很多与此主题相关的问题,但没有可靠的答案。所以我决定 post 我的解决方案作为这个问题的答案。 问题的上下文是检查“用户必须select列表框中的一项与可观察集合绑定”。
第一步,ObservableCollection
中的项目(实体)需要IsSelected
属性。
public class ProductDecorator : DecoratorBase<Product>
{
private string _ProductShortName;
private Boolean _IsSelected = false;
// I have omitted some code for clarity here.
public Boolean IsSelected
{
get { return _IsSelected; }
set
{
SetProperty(ref _IsSelected, value);
}
}
}
第二步,ObservableCollection
中的每一项都必须实现INotifyPropertyChanged
接口。然后你可以访问 PropertyChanged
事件处理程序。
第三步,您需要将以下方法附加到ObservableCollection
的CollectionChanged
事件处理程序。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
public SaleInvoiceViewModel() {
_productDecorators= new ObservableCollection<ProductDecorator>();
_productDecorators.CollectionChanged += ContentCollectionChanged;
}
public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach(ProductDecorator item in e.OldItems)
{
//Removed items
item.PropertyChanged -= EntityPropertyChanged;
}
}
else if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach(ProductDecorator item in e.NewItems)
{
//Added items
item.PropertyChanged += EntityPropertyChanged;
}
}
}
}
仔细看上面代码中的EntityPropertyChanged
方法。只要 ObservableCollection
中任何项目的任何属性发生更改,就会触发此方法。然后,你可以简单地在EntityPropertyChanged
方法中调用Validate
方法。
private void EntityPropertyChanged( object sender, PropertyChangedEventArgs e )
{
if (e.PropertyName == "IsSelected")
this.Product.ValidateProperty("ProductUmDecorators");
}
如果更改后的 属性 为 IsSelected
,则 ValidatedProperty
方法将为 运行。
我将省略 ValidateProperty
方法的详细实现。此方法将尝试使用 DataAnnotations
验证 属性 并在出现任何错误时触发 ErrorChanged 事件。可以详细了解here.
最后,您需要在 Entity/ViewModel/Decorator class 中实现自定义 DataAnnotation
ValidationAttribute
,其中您的 ObservableCollection
属性 如下所示代码。
public class SaleInvoiceViewModel {
private ObservableCollection<ProductDecorator> _productDecorators;
[AtLeastChooseOneItem(ErrorMessage = "Choose at least one item in the following list.")]
public ObservableCollection<ProductDecorator> ProductDecorators
{
get { return _productDecorators; }
set { SetProperty(ref _productDecorators, value); }
}
}
public class AtLeastChooseOneItem : ValidationAttribute
{
protected override ValidationResult IsValid( object value, ValidationContext validationContext )
{
ProductDecorator tmpEntity = (ProductDecorator) validationContext.ObjectInstance;
var tmpCollection = (ObservableCollection<ProductUmDecorator>) value;
if ( tmpCollection.Count == 0 )
return ValidationResult.Success;
foreach ( var item in tmpCollection )
{
if ( item.IsSelected == true )
return ValidationResult.Success;
}
return new ValidationResult( ErrorMessage );
}
}
这是一个有点复杂的解决方案,但这是迄今为止我找到的最可靠的解决方案。