2016-01-24 48 views
3

我正在開發WPF應用程序,使用MVVM模式並使用Prism框架。如何使用INotifyDataErrorInfo接口驗證Observable集合

我有一個基本的數據類如下。

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

而且我將這個可觀察集合綁定到View中的列表框。

<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> 

從上面的上下文中,我想驗證「用戶必須至少選擇列表框中的一個項目」。換句話說,IsSelected財產必須是ProductUmDecorator類從類可觀察收集ProductUmDecorators其中之一。

當前我使用INotifyDataErrorInfo接口和Data Annotations作爲驗證規則。我輸了我應該如何實現我的問題來實現這個驗證

+0

我已經去了一個SelectedProductUmDecorator聚會,並將其標記爲無效,如果是空的。你必須有其他的方式來表示集合中的選定元素[edit:duh,yeah],所以如果沒有選中任何一個,可能會嘗試將ProductUmDecorators標記爲無效? – Will

回答

2

在這個主題相關的計算器上有很多問題,但沒有確切的答案。所以我決定發佈我的解決方案作爲解決這個問題的答案。 問題的背景是檢查「用戶必須選擇列表框中與可觀察收集綁定的一個項目」。

第一步,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

第三步,您需要將以下方法附加到CollectionChanged事件處理程序ObservableCollection

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類中實現自定義DataAnnotationValidationAttribute,其中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); 
    } 
} 

這是一個有點複雜的解決方案,但這是迄今爲止我發現的最穩固的解決方案。