2010-02-27 38 views
6

Hoặc tôi không thấy giải pháp hoặc tôi đã tìm thấy sự cố khi sử dụng MVVM.Lỗ hổng MVVM sử dụng kịch bản Chi tiết chính

Tôi có mẫu này Master-Chi tiết:

class Customer 
{ 
    int CustomerID {get;set} 
    string Name {get;set} 
    ObservableCollection<Order> Orders {get;set} 
} 

class Order 
{ 
    int OrderID {get;set} 
    int Quantity {get;set} 
    double Discount {get;set} 
} 

Cho phép giả định trong CustomerOrdersViewModel ObservableCollection Khách hàng của tôi của tôi là ràng buộc với Xem qua ... = "{Binding khách hàng}" và khi khách hàng được thay đổi từ người sử dụng các đơn đặt hàng liên quan được hiển thị trong DataGrid thông qua ItemsSource = "{Binding SelectedItem.Orders, ElementName = comboboxCustomer}".

này có thể với MVVM:

tôi có thể thêm một khách hàng mới bằng cách đơn giản (để đơn giản) gọi Customers.Add(new Customer(){...});.

Sau khi thêm tôi làm điều này: this.RaisePropertyChanged("Customers");. Thao tác này sẽ cập nhật chế độ xem và hiển thị ngay lập tức Khách hàng trong Hộp chứa khách hàng.

Bây giờ đến phần không thể với MVVM.

tôi có thể thêm một thứ tự mới bằng cách SelectedCustomer.Orders.Add(New Order(){...});

NHƯNG tôi không thể nâng cao một sự kiện CollectionChanged/PropertyChanged như trước đây với Khách hàng bây giờ trên đơn đặt hàng vì Orders tài sản không bị ràng buộc vào Xem qua accessor công cộng .

Thậm chí nếu tôi sẽ phơi bày Orders tài sản bindable đến quan điểm, quan điểm riêng của mình chăm sóc cho Master-Detail chuyển đổi không phải là ViewModel ...

HỎI

Làm thế nào là nó có thể làm cho tổng thể -Detail Làm việc với các đối tượng Add/Del trong Details-List và cập nhật ngay trên View?

Trả lời

4

Điều này luôn khó khăn khi làm việc với chế độ xem chi tiết chính. Tuy nhiên, một tùy chọn thường tận dụng lợi thế của INotifyPropertyChanged và INotifyCollectionChanged, và tự theo dõi chúng trong ViewModel. Bằng cách theo dõi các thuộc tính này trên các đối tượng của bạn, bạn có thể xử lý thông báo một cách chính xác.

I blogged about a similar issue, nơi tôi muốn có tổng hợp xảy ra trong danh sách "chính" dựa trên giá trị trong ngăn chi tiết (ví dụ: hiển thị tổng số đơn đặt hàng, sẽ luôn được cập nhật). Các vấn đề là giống hệt nhau.

Tôi đặt một số working code up on the Expression Code Gallery minh họa cách bạn có thể xử lý theo dõi này và làm cho mọi thứ được cập nhật trong thời gian thực, trong khi vẫn giữ nguyên "thuần túy" trong điều khoản MVVM.

+1

Tôi đã kiểm tra mã của bạn và phải nói rằng nó làm cho quá phức tạp. WPF là tốt đẹp. MVVM làm cho mọi thứ trở nên phức tạp quá dễ dàng trong WinForms. Entity Framework là không thể với MVVM một trò đùa nếu bạn hỏi tôi. Hãy thử làm cho một Eager Loading với MVVM sau đó bạn biết những gì tôi có ý nghĩa. Mọi LOB đều có nhiều chi tiết chính. Bây giờ tôi biết tại sao mỗi mẫu MVVM ra có một bản demo ngu ngốc và đồng bộ Hiển thị tất cả danh sách khách hàng ... Nếu bạn biết về một mẫu MVVM Master-Detail khác, tôi sẽ đánh giá cao liên kết :) Vì những người quan tâm đến vấn đề đó: http://www.codeproject.com/KB/WPF/WpfNhibernateToolkit.aspx – msfanboy

+1

Thỏa thuận MVVM rất nhiều với quan hệ giữa View và ViewModel nhưng về VM quan hệ với Model hoàn toàn thầm lặng đoán tại sao? Bạn lấy Dữ liệu từ DAL của bạn và đọc các khách hàng, đơn đặt hàng, sản phẩm có liên quan trong 3 ObservableCollection ? Đây là một nỗ lực lớn tạo ra loại bối cảnh entityViewModel ... dường như quá nhiều devs chơi với VS2010 wpf RAD công cụ thiết kế để nhận ra các ứng dụng LOB thực cần nhiều hơn nữa ... – msfanboy

+0

Ahh - nhưng tôi không đồng ý ở đây. Có, mã phức tạp, nhưng nó hoàn toàn có thể tái sử dụng được. Sử dụng nó chỉ là kéo một hành vi vào danh sách chủ của bạn, và nó "chỉ hoạt động". –

0

Gần đây chúng tôi đã gặp phải một vấn đề tương tự, nhưng với yêu cầu bổ sung là Mô hình bao gồm các POCO ngu ngốc đơn giản.

Giải pháp của chúng tôi là áp dụng triệt để việc tách Model-ViewModel. Cả Model, cũng không phải ViewModel đều chứa ObservableCollection<ModelEntity>, thay vào đó Model chứa bộ sưu tập POCO và ViewModel chứa ObservableCollection<DetailViewModel>.

Điều đó dễ dàng giải quyết Thêm, Nhận và cập nhật. Ngoài ra, nếu chỉ có Master xóa một chi tiết từ bộ sưu tập của nó thì các sự kiện thích hợp sẽ được kích hoạt. Tuy nhiên, nếu các chi tiết yêu cầu xóa nó nhất thiết cần phải báo hiệu chủ (chủ sở hữu bộ sưu tập).

này có thể được thực hiện bằng cách lợi dụng sự kiện PropertyChanged:

class MasterViewModel { 
    private MasterModel master; 
    private ISomeService service; 
    private ObservableCollection<DetailViewModel> details; 

    public ObservableCollection<DetailViewModel> Details { 
    get { return this.details; } 
    set { return this.details ?? (this.details = LoadDetails()); } 
    } 

    public ObservableCollection<DetailViewModel> LoadDetails() { 
    var details = this.service.GetDetails(master); 
    var detailVms = details.Select(d => 
     { 
     var vm = new DetailViewModel(service, d) { State = DetailState.Unmodified }; 
     vm.PropertyChanged += this.OnDetailPropertyChanged; 
     return vm; 
     }); 

    return new ObservableCollection<DetailViewModel>(detailVms); 
    } 

    public void DeleteDetail(DetailViewModel detailVm) { 
    if(detailVm == null || detailVm.State != DetailState.Deleted || this.details == null) { 
     return; 
    } 

    detailVm.PropertyChanged -= this.OnDetailPropertyChanged; 

    this.details.Remove(detailVm); 
    } 

    private void OnDetailPropertyChanged(object s, PropertyChangedEventArgs a) { 
    if(a.PropertyName == "State" & (s as DetailViewModel).State == DetailState.Deleted) { 
     this.DeleteDetail(s as DetailViewModel); 
    } 
    } 
} 

class DetaiViewModel : INotifyPropertyChanged { 
    public DetailState State { get; private set; } // Notify in setter.. 

    public void Delete() { 
    this.State = DetailState.Deleted; 
    } 

    public enum DetailState { New, Unmodified, Modified, Deleted } 
} 

Thay vào đó bạn có thể giới thiệu một public event Action<DetailViewModel> Delete; trong DetailViewModel, ràng buộc trực tiếp để MasterViewModel::Delete vv

Nhược điểm để phương pháp này là bạn phải xây dựng rất nhiều ViewModels mà không bao giờ có thể cần thiết cho nhiều hơn tên của họ, vì vậy bạn thực sự cần phải tiếp tục xây dựng các ViewModels giá rẻ và đảm bảo rằng danh sách không phát nổ.

Ở phía trên, bạn có thể đảm bảo rằng giao diện người dùng chỉ liên kết với các đối tượng ViewModel và bạn có thể giữ rất nhiều vòng tròn INotifyPropertyChanged ra khỏi mô hình của bạn, giúp bạn cắt gọn giữa các lớp.

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