如何使用INotifyDataErrorInfo接口验证Observable Collection

4

我正在使用Prism框架,采用MVVM模式来开发WPF应用程序

以下是我的基本数据类。

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中创建了以上数据类的可观察集合。
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>

从上下文来看,我想验证“用户必须在列表框中选择至少一个项目”。换句话说,ProductUmDecorators可观察集合中的 ProductUmDecorator 类中的 IsSelected 属性必须为true
目前,我使用 INotifyDataErrorInfo 接口和 Data Annotations 进行验证规则。我不知道如何实现我的问题以实现此验证

我会选择一个SelectedProductUmDecorator组件,并在其为空时将其标记为无效。您必须有其他方法来指示集合中的选定元素[编辑:嗯,是的],因此,如果没有选择任何ProductUmDecorators,则可以尝试将其标记为无效? - user1228
1个回答

3

在stackoverflow上有很多与此主题相关的问题,但没有确定的答案。所以我决定将我的解决方案作为这个问题的答案。

问题的背景是要检查“用户必须在绑定了可观察集合的列表框中选择一个项目”。

第一步,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 事件处理程序。

第三步,需要将以下方法附加到 ObservableCollectionCollectionChanged 事件处理程序中。

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事件。您可以在此处了解详细信息:此处
最后,您需要在存在 ObservableCollection 属性的实体/视图模型/修饰器类中实现自定义 DataAnnotation ValidationAttribute ,如下所示:
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 );
    }
}

这是一个稍微复杂的解决方案,但是这是我迄今为止找到的最可靠的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接