2012-11-13 33 views
5

Tôi mới tham gia MVVM, vừa mới bắt đầu dự án đầu tiên của tôi theo mẫu MVVM. Tôi có một vấn đề cố gắng để xác nhận một ObservableCollection bằng cách sử dụng giao diện IDataErrorInfo. ObservableCollection của tôi trông như thế này:Xác nhận tính hợp lệ của ObservableCollection trong ViewModel bằng cách sử dụng mẫu MVVM

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

Và XAML của tôi như thế này:

<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}" /> 

Nó chỉ là một ListBox đơn giản có chứa các đối tượng, khi bạn chọn một mục, các thuộc tính đối tượng được chọn sẽ được hiển thị trong textbox, và sau đó được liên kết với đối tượng hộp danh sách.

Vấn đề của tôi là khi tôi thiết lập mã của mình như thế này, cách duy nhất tôi có thể tìm hiểu cách xác thực dữ liệu của mình là trong Mô hình miền, thực sự không phải là một phương pháp hay, tôi muốn xác nhận trong ViewModel trước khi nó đến đó. Về cơ bản tôi muốn xác nhận tính hợp lệ của từng thuộc tính trong MagazineRepository, trong ViewModel, bạn sẽ làm thế nào?

PS: Tôi mới đăng trên bảng này (và các bảng lập trình nói chung) nếu câu hỏi của tôi thiếu thông tin, vui lòng cho tôi biết và tôi sẽ cung cấp các chi tiết cần thiết.

Cảm ơn rất nhiều.

+0

Tôi không thấy một ViewModel trong mã của bạn mà bạn đã đăng, nhưng cách điển hình là để ViewModel của bạn triển khai IDataErrorInfo – Alan

+0

Xin lỗi, tôi nghĩ nó đã được ngụ ý.Bộ sưu tập nằm trong ViewModel của tôi, thực sự thực hiện IDataErrorInfo, nhưng khi hộp văn bản thay đổi thuộc tính trong bộ sưu tập, tôi cần phải xác thực thuộc tính đó và tôi không thể tìm ra chính xác cách thực hiện điều đó. Vì vậy, có 2 hộp văn bản từng bị ràng buộc vào một thuộc tính trong bộ sưu tập, và khi thay đổi thuộc tính đó tôi cần phải xác thực trên nó, làm theo cách tôi đã học với IDataErrorInfo tôi chỉ có thể xác nhận toàn bộ bộ sưu tập. –

Trả lời

3

Nếu tôi hiểu chính xác bạn muốn xác thực đối tượng Tạp chí. Nếu đó là trường hợp, một cách để làm điều đó là để bọc lớp đó trong một viewmodel, hãy gọi nó là MagazineVM, thực hiện IDataErrorInfo và giữ cho đối tượng tạp chí được cập nhật. Sau đó, bạn liên kết với chế độ xem danh sách MagazineVM. Như một ví dụ rất đơn giản:

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

Thứ nhất, như dtex nói, bạn nên sử dụng một lớp MagazineViewModel chứ không phải là một lớp Magazine. VÍ DỤ.

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

} 

Thuộc tính quan trọng cần lưu ý là "chuỗi công khai [string columnName]" này. ColumnName sẽ là một trong các thuộc tính ràng buộc của bạn và đây là nơi bạn có thể thực hiện xác nhận hợp lệ.

Điều tiếp theo cần xem xét là MainViewModel (DataContext của bạn). VÍ DỤ.

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) 
    { 
    //... 
    } 
} 

Điều duy nhất còn thiếu ở đây là cách bạn sao chép các thay đổi về kiểu xem ban đầu. Bạn có thể làm điều đó trước khi mục được chọn thay đổi (nếu ItemToEdit hợp lệ) hoặc có nút Commit chỉ được kích hoạt khi ItemToEdit hợp lệ. Nếu bạn có thể cho phép các kiểu xem ban đầu của mình đi vào trạng thái không hợp lệ, bạn không cần lo lắng về việc sao chép.

Cuối cùng XAML

Một phong cách ngầm để hiển thị tooltip lỗi

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

Và các điều khiển và bindings

<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}" /> 

textbox liên kết với ItemToEdit. ItemToEdit sẽ là một bản sao không đồng bộ của SelectedItem.

Các vấn đề liên quan