2012-11-13 58 views
5

我是MVVM的新手,剛剛在MVVM模式之後啓動了我的第一個項目。我有一個問題試圖使用IDataErrorInfo接口來驗證ObservableCollection。我的ObservableCollection看起來是這樣的:使用MVVM驗證ViewModel中綁定的ObservableCollection模式

ObservableCollection<Magazine> magazineRepository; 
    public ObservableCollection<Magazine> MagazineRepository 
    { 
     get { return magazineRepository; } 
     set 
     { 
      if (value != null) 
      { 
       bladRepository = value; 
       OnPropertyChanged("MagazineRepository"); 
      } 
     } 
    } 

我的XAML這樣的:

<ListBox x:Name="listMagazineRepository" 
       Grid.ColumnSpan="2" 
       ItemsSource="{Binding}" 
       DataContext="{Binding MagazineRepository}" 
       DisplayMemberPath="Navn" 
       SelectedItem="{Binding Path=SelectedItem}"/> 

     <TextBox x:Name="txtName" Grid.Row="1" Grid.Column="0" 
        Text="{Binding ElementName=listMagazineRepository, Path=SelectedItem.Navn, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> 
     <TextBox x:Name="txtPrice" Grid.Row="2" Grid.Column="0" 
        Text="{Binding ElementName=listMagazineRepository, Path=SelectedItem.Pris, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> 

,當你選擇一個項目,所選對象的屬性顯示在文本框,它只是包含對象的簡單列表框然後綁定到列表框對象。

我的問題是,當我像這樣設置我的代碼時,唯一可以弄清楚如何驗證數據的方法是在域模型中,這實際上不是一種好的做法,我想在它到達那裏之前在ViewModel中驗證。基本上我想驗證MagazineRepository中的每個屬性,在ViewModel中,你將如何去做這件事?如果我的問題缺乏信息,請讓我知道,我將提供所需的詳細信息。如果我的問題缺乏信息,請告訴我,我將提供所需的詳細信息。

非常感謝。

+0

嗯,我沒有在您的代碼中看到您發佈的ViewModel,但典型的方式將是您的ViewModel實現IDataErrorInfo – Alan

+0

對不起,我認爲這是暗示。該集合在我的ViewModel中,確實實現了IDataErrorInfo,但是當文本框更改集合中的一個屬性時,我需要驗證該屬性,並且我無法弄清楚該怎麼做。所以有兩個文本框每個綁定到集合中的一個屬性,當屬性發生變化時,我需要對它進行驗證,按照我使用IDataErrorInfo學習的方式進行驗證,我只能驗證整個集合。 –

回答

3

如果我理解正確,你想驗證雜誌對象。如果是這樣的話,一種方法是將該類封裝在視圖模型中,我們稱之爲MagazineVM,它實現IDataErrorInfo並保持雜誌對象的更新。然後,您將視圖綁定到MagazineVM的列表。作爲一個非常簡單的例子:

public class MagazineVM : IDataErrorInfo, INotifyPropertyChanged 
{ 
    private Magazine _magazine; 

    public int FirstMagazineProperty 
    { 
     get { return _magazine.FirstMagazineProperty; } 
     set { _magazine.FirstMagazineProperty = value; RaisePropertyChanged("FirstMagazineProperty"); } 
    } 

    //INotifyPropertyChanged implementation 

    //IDataErrorInfo implementation 
} 
3

首先,正如Dtex所說,您應該使用MagazineViewModel類而不是Magazine類。例如。

public class MagazineViewModel : INotifyPropertyChanged, IDataErrorInfo 
{ 
    private string navn; 
    private string pris; 
    private string error; 

    public string Navn 
    { 
    get { return navn; } 
    set 
    { 
     if (navn != value) 
     { 
     navn = value; 
     RaisePropertyChanged("Navn"); 
     } 
    } 
    } 
    public string Pris 
    { 
    get { return pris; } 
    set 
    { 
     if (pris != value) 
     { 
     pris = value; 
     RaisePropertyChanged("Pris"); 
     } 
    } 
    } 
    public string Error 
    { 
    get { return error; } 
    set 
    { 
     if (error != value) 
     { 
     error = value; 
     RaisePropertyChanged("Error"); 
     } 
    } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public string this[string columnName] 
    { 
    get 
    { 
     var result = string.Empty; 

     switch (columnName) 
     { 
     case "Pris": 
      if (string.IsNullOrWhiteSpace(Pris)) 
      { 
      result = "Pris is required"; 
      } 
      break; 
     case "Navn": 
      if (string.IsNullOrWhiteSpace(Navn)) 
      { 
      result = "Navn is required"; 
      } 
      break; 
     } 

     return result; 

    } 
    } 

    private void RaisePropertyChanged(string PropertyName) 
    { 
    var e = PropertyChanged; 
    if (e != null) 
    { 
     e(this, new PropertyChangedEventArgs(PropertyName)); 
    } 
    } 

} 

要注意的重要屬性是「public string this [string columnName]」。 ColumnName將是你的綁定屬性之一,這是你可以進行驗證的地方。

接下來要考慮的是您的MainViewModel(您的DataContext)。例如。

public class MainViewModel : INotifyPropertyChanged 
{ 
    //Use a readonly observable collection. If you need to reset it use the .Clear() method 
    private readonly ObservableCollection<MagazineViewModel> magazines = new ObservableCollection<MagazineViewModel>(); 

    private MagazineViewModel selectedItem; 

    //Keep the item being edited separate to the selected item 
    private MagazineViewModel itemToEdit; 

    public ObservableCollection<MagazineViewModel> Magazines { get { return magazines; } } 
    public MagazineViewModel SelectedItem 
    { 
    get { return selectedItem; } 
    set 
    { 
     if (selectedItem != value) 
     { 
     selectedItem = value; 
     RaisePropertyChanged("SelectedItem"); 
     //When the selected item changes. Copy it to the ItemToEdit 
     //This keeps the the copy you are editing separate meaning that invalid data isn't committed back to your original view model 
     //You will have to copy the changes back to your original view model at some stage) 
     ItemToEdit = Copy(SelectedItem); 
     } 
    } 
    } 
    public MagazineViewModel ItemToEdit 
    { 
    get { return itemToEdit; } 
    set 
    { 
     if (itemToEdit != value) 
     { 
     itemToEdit = value; 
     RaisePropertyChanged("ItemToEdit"); 
     } 
    } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public MainViewModel() 
    { 
    //Ctor... 
    } 

    //Create a copy of a MagazineViewModel 
    private MagazineViewModel Copy(MagazineViewModel ToCopy) 
    { 
    var vm = new MagazineViewModel(); 
    vm.Navn = ToCopy.Navn; 
    vm.Pris = ToCopy.Pris; 
    return vm; 
    } 

    private void RaisePropertyChanged(string PropertyName) 
    { 
    //... 
    } 
} 

這裏唯一缺少的就是將更改複製回原始視圖模型。您可以在所選項目更改(如果ItemToEdit有效)之前執行此操作,或者只有在ItemToEdit有效時才啓用「提交」按鈕。如果您可以允許原始視圖模型進入無效狀態,則不必擔心複製。

最後的XAML

隱式風格,顯示錯誤提示

<Style 
    TargetType="{x:Type TextBox}"> 
    <Setter 
    Property="ToolTip" 
    Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" /> 
</Style> 

與對照組和綁定

<ListBox 
    ItemsSource="{Binding Magazines}" 
    DisplayMemberPath="Navn" 
    SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}" /> 
<TextBox 
    Margin="5" 
    x:Name="txtName" 
    Grid.Row="1" 
    Grid.Column="0" 
    Text="{Binding ItemToEdit.Navn, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> 
<TextBox 
    Margin="5" 
    x:Name="txtPrice" 
    Grid.Row="2" 
    Grid.Column="0" 
    Text="{Binding ItemToEdit.Pris, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" /> 

文本框綁定到ItemToEdit。 ItemToEdit將是SelectedItem的同步副本。

相關問題