2012-08-08 44 views
10

我有一個Person類:實施INotifyPropertyChanged的嵌套性

public class Person : INotifyPropertyChanged 
{ 
    private string _name; 
    public string Name{ 
    get { return _name; } 
    set { 
      if (_name != value) { 
      _name = value; 
      OnPropertyChanged("Name"); 
      } 
    } 

    private Address _primaryAddress; 
    public Address PrimaryAddress { 
    get { return _primaryAddress; } 
    set { 
      if (_primaryAddress != value) { 
      _primaryAddress = value; 
      OnPropertyChanged("PrimaryAddress"); 
      } 
    } 

    //OnPropertyChanged code goes here 
} 

我有一個Address類:

public class Address : INotifyPropertyChanged 
{ 
    private string _streetone; 
    public string StreetOne{ 
    get { return _streetone; } 
    set { 
      if (_streetone != value) { 
      _streetone = value; 
      OnPropertyChanged("StreetOne"); 
      } 
    } 

    //Other fields here 

    //OnPropertyChanged code goes here 
} 

我有一個視圖模型:

public class MyViewModel 
{ 
    //constructor and other stuff here 

    private Person _person; 
    public Person Person{ 
    get { return _person; } 
    set { 
      if (_person != value) { 
      _person = value; 
      OnPropertyChanged("Person"); 
      } 
    } 

} 

我有一個觀點其中有以下幾行:

<TextBox Text="{Binding Person.Name, Mode=TwoWay, 
    UpdateSourceTrigger=PropertyChanged /> 

<TextBox Text="{Binding Person.Address.StreetOne, Mode=TwoWay, 
    UpdateSourceTrigger=PropertyChanged /> 

這兩個值都顯示在文本框中,當視圖加載時就ok了。

對第一個文本框的更改將在MyViewModel中觸發OnPropertyChanged("Person")。大。

對第二個文本框("Person.Address.StreetOne")的更改不會在MyViewModel中激發OnPropertyChanged("Person")。這意味着它不會調用Person對象的SET方法。不是很好。有趣的是,Address類中的StreetOne的SET方法被調用。

Person.Address.StreetOne被更改時,如何獲得ViewModel中的Person對象的SET方法?

我是否需要將我的數據變平,以便SteetOne在Person內而不是Address?

謝謝!

+1

@相關...關於你的恩惠問題已經回答了。那麼你在這裏尋找什麼樣的答案? – 2016-03-10 12:20:15

+0

@ S.Akbari:接受的答案是一種解決方法,它將財產壓平。我正在尋找一個真正的解決方案 – Revious 2016-03-10 13:28:27

+1

@Revious我使用標準的替代方法添加了一個答案,即使用事件處理程序將更改從子項傳播到父項。我不確定這在最初的答案中是如何被忽略的,因爲它是相當標準和「真正」的解決方案。 – 2016-03-11 17:09:54

回答

8
如果你想在視圖模型設置爲叫你可以創建一個街道性質

public class MyViewModel 
{ 
    //constructor and other stuff here 
    public string Street{ 
    get { return this.Person.PrimaryAddress.StreetOne; } 
    set { 
     if (this.Person.PrimaryAddress.StreetOne!= value) { 
     this.Person.PrimaryAddress.StreetOne = value; 
     OnPropertyChanged("Street"); 
     } 
    } 

} 

xaml

<TextBox Text="{Binding Street, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged /> 

但這種解決方案有其缺點。我與我的項目中的蘆葦回答

+0

感謝您的回覆。這種方式確實有效(我還不能投票,否則我會)。我想這是一個辯論是否這樣做或平掉我的人類是一個更好的選擇。我會與蘆葦回答,但我不知道他的意思是「你必須手動訂閱PropertyChanged事件」。我已經在地址,人員和MyViewModel級別上實現了OnPropertyChanged ... – 2012-08-09 16:49:03

+0

最後,我非常喜歡這條路線。上述方法可行,但不是將上面的代碼放置在視圖模型中,而是將其添加到Person類中。所以基本上我有一個叫SreetOneDisplay的刺痛。所以我沒有真正把我的模型弄平,還有一個地址類。 – 2012-08-14 18:18:41

4

如何在Person.Address.StreetOne更改時調用ViewModel中Person對象的SET方法?

你爲什麼要這麼做?不應該要求 - 你只需要觸發StreetOne屬性更改事件。

我是否需要將我的數據變平,以便SteetOne在Person內而不是Address?

如果你想要真正引起這種觸發,你不需要扁平化(雖然這是一個選項)。您可以在您的Person類中訂閱AddressPropertyChanged事件,並在Person內發生更改時提升「地址」事件。但是,這不應該是必需的。

+0

感謝您的迴應!讓我試着澄清。在'(「Person.Address.StreetOne」)'文本框更改時,MyViewModel內部沒有任何反應。我希望Person的SET方法像Person.Name更改時一樣觸發。此外,即使Address類中的StreetOne的SET方法被調用,但在調用「OnPropertyChanged(」SteetOne「)」時似乎沒有任何事情發生。不調用Person類中的PrimaryAddress的SET方法。 – 2012-08-08 18:50:42

+1

@lloydchristmas爲什麼你想要它被稱爲,但? WPF不需要調用它。如果你希望它被調用,你必須手動訂閱PropertyChanged事件... – 2012-08-08 18:52:30

+0

當Person的SET方法被調用時,我會做一些其他驗證調用。所以任何時候人更改我運行一些驗證。例如,當更改StreetOne時,我需要驗證它是一個有效的地址......類似的東西。那麼如何手動訂閱PropertChanged事件?謝謝。 – 2012-08-08 19:02:15

0

。在你的屬性更改通知拼寫錯誤:

OnPropertyChanged("SteetOne");

應該

OnPropertyChanged("StreetOne");

+0

謝謝,我解決了它。不是問題,但。真的,這只是我編造的一個例子。 – 2012-08-08 21:15:45

1

因爲我無法找到一個現成的解決方案,我做了一個基於Pieters(和Marks)建議(謝謝!)的自定義實現。

中的類,你會被通知在一個很深的對象樹的任何變化,這適用於任何INotifyPropertyChanged實施類型和INotifyCollectionChanged *實現集合(很顯然,我使用的是ObservableCollection爲)。

我希望這是一個相當乾淨和優雅的解決方案,雖然沒有經過充分測試,並且還有增強空間。這是很容易使用,使用它的靜態Create方法,並把您的INotifyPropertyChanged剛剛創建的ChangeListener一個實例:

var listener = ChangeListener.Create(myViewModel); 
listener.PropertyChanged += 
    new PropertyChangedEventHandler(listener_PropertyChanged); 

PropertyChangedEventArgs提供PropertyName這將是永遠的對​​象的完整「路徑」。例如,如果您更改人物的「最佳朋友」名稱,則PropertyName將爲「最佳朋友名稱」,如果BestFriend有一組兒童,並且您更改了其年齡,則值將爲「最佳朋友。兒童[]。年齡」等等。當你的對象被銷燬時,不要忘記Dispose,那麼它將(希望)完全取消所有事件監聽器的訂閱。

它在.NET(測試4)和Silverlight(測試4)編譯。由於分隔在三個類的代碼,我已經張貼代碼gist 705450在那裏你可以抓住這一切:https://gist.github.com/705450 **

*)的原因之一,該代碼工作是,ObservableCollection也實現INotifyPropertyChanged,否則根據需要它不會工作,這是一個已知警告

**)免費使用,在MIT License

4

釋放,而加入「直通」屬性,你的視圖模型是一個很好的解決方案,它可以很快變得站不住腳。標準的選擇是傳播如下變化:

public Address PrimaryAddress { 
    get { return _primaryAddress; } 
    set { 
      if (_primaryAddress != value) 
      { 
      //Clean-up old event handler: 
      if(_primaryAddress != null 
       _primaryAddress.PropertyChanged -= AddressChanged; 

      _primaryAddress = value; 

      _primaryAddress.PropertyChanged += AddressChanged; 

      OnPropertyChanged("PrimaryAddress"); 
      } 
    } 

    private void AddressChanged(object sender, PropertyChangedEventArgs args) 
    { 
     OnPropertyChanged("PrimaryAddress"); 
    } 

現在更改通知從地址傳播到人員。

相關問題