2010-01-05 30 views
15

Hãy nói rằng trong một số ViewModel trừu tượng cơ sở lớp tôi có một tài sản đồng bằng tuổi như sau:Thông báo Thay đổi trong MVVM tầng nấc

public Size Size 
{ 
    get { return _size; } 
    set 
    { 
     _size = value; 
     OnPropertyChanged("Size"); 
    } 
} 

sau đó tôi tạo ra một ViewModel cụ thể hơn, kế thừa từ trước đó, trong đó có các tài sản sau đây:

public Rect Rectangle 
{ 
    get { return new Rect(0, 0, _size.Width, _size.Height); } 
} 

Bây giờ, trong một số lớp View tôi liên kết với tài sản Rectangle nói trên ViewModel của. Tất cả mọi thứ hoạt động tốt, cho đến khi tôi thay đổi kích thước. Khi Size thay đổi, Rectangle không biết về thay đổi đó và thay đổi không lan truyền đến Chế độ xem. Và kể từ khi Rectangle là trong lớp trẻ em, tôi không thể chỉ cần thêm một OnPropertyChanged("Rectangle") vào thiết lập Size.

Bây giờ hãy tưởng tượng rằng tôi có nhiều thuộc tính khác nhau như Rectangle, tất cả đều phụ thuộc vào thuộc tính cấp cơ sở và không có thay đổi nào trong số những thay đổi này đang được phổ biến. Tôi cần một số thông báo thay đổi chuỗi nhẹ và thanh lịch, tốt nhất là không yêu cầu nhiều mã và không buộc tôi sử dụng các thuộc tính phụ thuộc.

Rõ ràng là có rất nhiều giải pháp xấu xí ở đây- những gì tôi đang tìm kiếm là thứ gì đó sạch sẽ và thông minh. Dường như với tôi đây sẽ là một kịch bản rất phổ biến, và có vẻ như với tôi có thể có một cách MVVM thân thiện với cách thực hiện việc này.

Trả lời

9

Gần đây, tôi đã viết blog về vấn đề chính xác này. Tôi bao gồm thuộc tính [DependsUpon("Size")] bằng Hình chữ nhật. Tôi thực sự thích cách tiếp cận này, bởi vì nó giữ kiến ​​thức phụ thuộc với mã tạo ra sự phụ thuộc, không phải là cách khác xung quanh.

Hãy xem: http://houseofbilz.com/archive/2009/11/14/adventures-in-mvvm----dependant-properties-with-inotifypropertychanged.aspx

+0

Ý tưởng tuyệt vời. Tôi đã thay đổi nó một chút để tạo ra một từ điển tại thời điểm xây dựng (vì lý do hiệu suất), nhưng khái niệm là âm thanh. – Charlie

3

Bạn chỉ có thể ghi đè OnPropertyChanged trong ViewModel có nguồn gốc như vậy:

protected override void OnPropertyChanged(string propertyName) { 
    base.OnPropertyChanged(propertyName); 
    if (propertyName == "Size") { 
     base.OnPropertyChanged("Rectangle"); 
    } 
} 

Một khả năng ... Một khi trở lại tôi đặt cùng một lớp cơ sở ViewModel khá đẹp có hỗ trợ các thuộc tính trên tài sản như:

[DependsOn("Size")] 
public Rect Rectangle { 
    get { new Rect(0,0,Size.Width, Size.Height); } 
} 

Sau đó lớp cơ sở ViewModel thu thập DependsOnAttribute lúc chạy và trong phương pháp OnPropertyChanged của nó về cơ bản, chỉ cần xem những thuộc tính khác cần phải làm mất hiệu lực khi thuộc tính chang e xảy ra.

+0

Ghi đè OnPropertyChanged chắc chắn là một giải pháp, nhưng không phải là giải pháp thanh lịch. Tôi thích đề xuất thứ hai của bạn tốt hơn, mặc dù. – Charlie

+0

Không phải tất cả các giải pháp đều kêu gọi sự sang trọng. Ghi đè OnPropertyChanged là rất đơn giản và tôi vẫn làm điều đó trong nhiều trường hợp, trừ khi các phụ thuộc nhận được lông mà dẫn tôi làm cách tiếp cận thứ 2. – Josh

+0

Bạn nói đúng, nhưng hãy nhớ trong câu hỏi của tôi tôi đã nói, "Bây giờ hãy tưởng tượng rằng tôi có nhiều thuộc tính khác nhau như Rectangle, tất cả đều phụ thuộc vào thuộc tính cơ sở, và không ai trong số những thay đổi này đang được truyền bá." Vì vậy, giả định là hệ thống phân cấp đã nhận được lông. – Charlie

1

Một MVVM cách sạch sẽ được sử dụng một đăng ký/thông báo cho cơ chế Messenger (như trong Giô-suê Smith MvvmFoundation)

Tạo Messenger đối tượng singleton nơi nào đó - lớp App chính luôn là một nơi tốt cho việc này

public partial class App : Application 
{ 
    private static Messenger _messenger; 
    public static Messenger Messenger 
    { 
     get 
     { 
      if (_messenger == null) 
      { 
       _messenger = new Messenger(); 
      } 
      return _messenger; 
     } 
    } 
} 

Trong Kích setter từ lớp cơ sở, thông báo thay đổi:

public Size Size 
{ 
    get { return _size; } 
    set 
    { 
     _size = value; 
     OnPropertyChanged("Size"); 

     App.Messenger.NotifyColleagues("SIZE_CHANGED"); 
    } 
} 

Bây giờ bạn có thể cho Xem kế thừa của bạn Mô hình của lắng nghe những thay đổi này, và nâng cao PropertyChanged sự kiện phù hợp ...

public MyViewModel : MyViewModelBase 
{ 
    public MyViewModel() 
    { 
     App.Messenger.Register("SIZE_CHANGED",() => OnPropertyChanged("Rectangle")); 
    } 
} 

Tất nhiên - bạn có thể thêm bao nhiêu đăng ký để thông điệp này khi bạn cần - một cho mỗi tài sản mà cần thay đổi để được thông báo trở lại Xem ...

Hope this helps :)

+0

Điều này chỉ chính xác giống như OnPropertyChanged ghi đè cho đứa trẻ trong cha mẹ, không chắc chắn nó thực sự làm cho nó sạch hơn – AwkwardCoder

+0

Đây không phải là một ý tưởng tồi chút nào, nhưng tôi muốn thứ gì đó nhẹ hơn một chút. – Charlie

+0

Lợi ích của việc sử dụng một cách tiếp cận Messenger có thể là trong trường hợp bạn có hệ thống phân cấp lồng nhau sâu sắc nơi nó sẽ bất tiện và có lẽ không hiệu quả để chuỗi các sự kiện thay đổi tài sản. – jpierson

0

có lẽ vì im một chàng trai VB, nhưng trong mã Rectangle của bạn có vẻ như bạn đang truy cập vào tờ khai _size tin thay vì tài sản Kích Công mà sẽ không cháy, sự kiện OnPropertyChanged để cảnh báo chế độ xem.

Ngoài ra tôi có thể là cơ sở, nhưng hình chữ nhật không nên là một đối tượng thực tế trong khi kích thước là một tài sản của đối tượng đó? Có lẽ đó là những gì bạn đang làm .. một số phương pháp luận C# vẫn còn thực sự xa lạ với tôi.

+0

Tôi đang sử dụng khai báo _size riêng tư nhưng nó không liên quan. Đó là một getter, không phải là một setter. Khung nhìn cần được thông báo rằng Rectangle đang thay đổi khi Size thay đổi, không phải khi Rectangle đang được truy cập. – Charlie

4

tôi sử dụng PropertyObserver Josh Smith, mà bạn có thể nhận được từ thư viện MVVM Foundation của mình tại http://mvvmfoundation.codeplex.com/.

Cách sử dụng:

_viewmodel_observer = new PropertyObserver<OtherViewModel>(_OtherViewModel) 
    .RegisterHandler(m => m.Size, m => RaisePropertyChanged(Rectangle); 

cách tiếp cận thuộc tính của Brian là đẹp quá. Một điều tôi thích về PropertyObserver là tôi có thể thực thi mã tùy ý; cho phép tôi kiểm tra các điều kiện có thể khiến tôi tránh được việc nâng cao hoặc thực hiện các hành động khác cùng nhau.

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