2010-11-04 21 views
8

Theo như tôi phát triển ứng dụng WPF với MVVM, tôi không bao giờ phơi bày mô hình thông qua tài sản công khai của viewmodel. Dù sao thì, sau khi tôi mới đến thế giới của Silverlight và WCF RIA, tôi đã tìm ra phương pháp mới để đạt được xác nhận dữ liệu, điều đó được nói bởi thuộc tính Bắt buộc. (cũng có những thuộc tính khác)Tại sao không tốt để hiển thị Mô hình thông qua ViewModel trong Silverlight MVVM?

Lần này thay vì tạo logic xác nhận bên trong viewmodel, tôi có thể thực hiện hầu hết logic xác thực bên trong chính mô hình đó.

public class TestUserPM { 
    [Key] 
    public int ID { get; set; } 

    [Required] 
    public string FirstName { get; set; } 

    [Required] 
    public string Email { get; set; } 
} 

Sau đó, tất cả những gì tôi cần trong ViewModel là hiển thị thuộc tính công khai của loại TestUserPM và để Xem ràng buộc trực tiếp với mô hình.

Tôi nghĩ đây không phải là giải pháp thanh lịch nhưng nó có thể hoạt động và không cần phải tạo ra xác thực tẻ nhạt bên trong thuộc tính viewmodel.

Có bất kỳ phần nào của phương pháp này không?

Cập nhật 1

Tôi chỉ tìm thấy 1 xuống phía, có thể nó có giải pháp ra khỏi đó. Tôi muốn ràng buộc Command của Button, ví dụ, nút lưu vào Command trong ViewModel nhưng nút này có thể thực hiện nếu và chỉ khi tất cả các thông tin là hợp lệ. Từ kinh nghiệm của tôi với WPF MVVM mà tôi đã giúp đỡ lớp tôi sẽ gọi OnCanExecuteChanged() bên trong public string this[string columnName] của IDataErrorInfo.

Tôi có thể xử lý như thế nào với loại yêu cầu này?

Trả lời

10

Tôi phơi bày Mô hình thông qua ViewModel mọi lúc, chỉ để giữ cho mọi thứ đơn giản và không lặp lại (DRY).

Điều duy nhất để tránh sự cần thiết phải thêm thuộc tính trong mô hình để thích ứng với giao diện người dùng (như Benjamin ghi chú), là giữ mô hình như một tính thích hợp của viewModel, vì vậy bạn có thể thêm các thuộc tính vào viewModel, làm rối loạn mô hình.

ví dụ: Các ViewModel là DataContext và nó có một tài sản Mẫu trở về mô hình

<TextBlock Text={Binding Path=Model.Name} /> 
<TextBlock Text={Binding Path=Model.Address} /> 
+2

Tôi cũng làm như vậy. ViewModel là ở đây để lộ và thích ứng với các mô hình để xem. –

+0

Ý tưởng sử dụng Mô hình trực tiếp vi phạm quy tắc của Encapsulationbecause không ai nên làm 'MyObject.Child.ChildChild.NChild.SomeProperty'. Ngoài ra nó là một lần nữa sự tách biệt giữa Model và View bởi vì nếu bạn thay đổi Propertyname trong Model của bạn, bạn phải thực hiện nó trong View/'s – WiiMaxx

4

Vấn đề chính mà tôi thấy là mô hình của bạn (có thể là đối tượng kinh doanh), phải thích nghi với giao diện người dùng. Nó có thể tác động đến rất nhiều UI hoặc lớp kinh doanh khác.

Bạn có thể tưởng tượng một số giao diện người dùng có các mức xác thực khác nhau trên cùng một đối tượng. Điều này là không thể với ví dụ của bạn.

1

Bạn đúng để sử dụng xác thực qua chú thích trong Silverlight, thay vì điền vào một ViewModel bằng mã.

Trong trường hợp của bất kỳ quy tắc xác thực đặc biệt nào, bạn có thể tạo trình xác thực tùy chỉnh và trang trí các thành viên bằng [CustomValidation ...], một lần nữa sẽ giữ xác thực khỏi ViewModel.

Trong mọi trường hợp, quy tắc kinh doanh mà bạn mô tả thường được chia sẻ trên các chế độ xem. Xác thực cụ thể, cho các khung nhìn trường hợp đặc biệt, có thể được thêm vào trong bộ điều khiển.

Như một điểm chung: một ViewModel là một đối tượng tương đối câm để giữ giá trị cho một chế độ xem. Nếu bạn bắt đầu tìm thấy bạn đang thêm logic, xử lý sự kiện và khác, bạn có lẽ nên xem xét giới thiệu một đối tượng điều khiển ... mặc dù không có C trong MVVM :)

+0

Tôi chỉ đọc chúng từ các tài liệu và tôi không hiểu, tại sao chúng ta cần phải tiêm ViewModel giống như trực tiếp từ dịch vụ? Đây là nhiệm vụ liên quan đến giao diện người dùng, nó phải ở cấp UI, không phải là dịch vụ. (theo ý kiến ​​của tôi) Về cơ bản, điều này có nghĩa là tôi cần phải đưa mọi thứ vào Dịch vụ, thật lạ lẫm đối với tôi. :) – Anonymous

+0

@In The Pink: Tôi xin lỗi tôi không hiểu câu hỏi của bạn (dịch vụ nào bạn muốn nói, dịch vụ RIA?). ViewModel là giao diện người dùng, nhưng các mô hình dữ liệu mà nó hiển thị là các đối tượng kinh doanh được điền từ một dịch vụ web. Với việc xác thực dịch vụ RIA có thể xảy ra trên cả hai phía máy khách và dịch vụ. –

1

Để vạch trần Model trong ViewModel, bạn cần chuẩn bị mẫu của bạn để thích ứng View, do đó bạn nên làm ô nhiễm Model của bạn với quan điểm mã cụ thể:

  • Thông báo cho tài sản Change hỗ trợ
  • dữ liệu Lỗi Thông tin hỗ trợ (Validation bên trong)
  • hỗ trợ Editable .

Điều cần thiết là không gây ô nhiễm Mô hình của bạn với điều khác, mô hình hoàn hảo phải có phụ thuộc tối thiểu với thư viện khác, vì vậy nó có thể được chia sẻ trong cùng một ứng dụng với nền tảng khác nhau (asp.net, di động, mono, winform, wpf, v.v.) Hoặc để nâng cấp/hạ cấp.

anyway ..

tôi đã thực hiện một small WPF application (chưa hoàn thành), tôi sử dụng uNhAddins, NHibernate, Lâu đài để xây dựng nó. Tôi không nói đó là giải pháp tốt nhất nhưng tôi thực sự hạnh phúc khi làm việc với nó .. Kiểm tra mã đầu tiên sau đó nhìn thấy sự tách biệt của thực thể, Validation Logic, Business Logic. Việc tách lắp ráp được thiết kế để giảm thiểu sự phụ thuộc giữa ứng dụng cốt lõi, giao diện người dùng và logic ứng dụng.

4

Vấn đề là vì những người khác đã nói rằng bạn không thể điều chỉnh chế độ xem. Tuy nhiên tôi thường không muốn lặp lại bản thân mình - như Eduardo cũng nói với sự tiếp xúc của mô hình để liên kết với. Tôi thấy rằng giải pháp là một chút không nhất quán khi bạn muốn thay đổi giá trị cho chế độ xem - sau đó một số sẽ ràng buộc "Model.Name" và một số khác chỉ là "Tên" cho thuộc tính bị thay đổi - và một số kịch bản chỉ giành được ' t làm việc theo cách đó.

Giải pháp của tôi là tạo lớp ViewModelProxy nơi bạn có thể chuyển tiếp các thuộc tính từ một lớp khác và nhận thông báo thuộc tính miễn phí. Nó được thực hiện khá dễ dàng bằng cách lấy ra DynamicObject (tôi đã để lại thông báo mã, IDataerror, vv). Điều thú vị là tất cả các thuộc tính từ Dữ liệu được chuyển tiếp - nếu bạn triển khai/ghi đè thuộc tính sẽ được ràng buộc - vì vậy theo cách này bạn không phải lặp lại mã và bạn có một điều hợp lý để sử dụng DynamicObject.

public class ViewModelProxy<T> : DynamicObject, INotifyPropertyChanged 

public T Data { get; set; } 

private PropertyInfo[] objectProperties; 
private PropertyInfo[] ObjectProperties 
{ 
    get 
    { 
    if (objectProperties == null) 
     objectProperties = typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 
    return objectProperties; 
    } 
} 
public override bool TryGetMember(GetMemberBinder binder, out object result) 
{ 
    var pinfo = ObjectProperties.FirstOrDefault((pi) => pi.Name == binder.Name); 

    if (pinfo != null) 
    { 
    result = Data != null ? pinfo.GetValue(Data, null) : null; 
    return true; 
    } 
    else 
    return base.TryGetMember(binder, out result); 
} 


public override bool TrySetMember(SetMemberBinder binder, object value) 
{ 
    var pinfo = ObjectProperties.FirstOrDefault((pi) => pi.Name == binder.Name); 

    if (pinfo != null) 
    { 
    if (Data != null) 
     pinfo.SetValue(Data, value, null); 
    RaisePropertyChanged(binder.Name); 
    return true; 
    } 
    else 
    return base.TrySetMember(binder, value); 
} 

}

+0

Và hiệu suất như thế nào? Có vẻ như nó sẽ làm chậm nó một chút ... Không? –

+0

Hiệu suất là tốt. Tất nhiên là có một chi phí nhỏ, nhưng các cuộc gọi phản ánh không đắt. Nếu bạn có nhiều thuộc tính, bạn có thể trao đổi tra cứu mảng bằng tra cứu từ điển. –

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