为嵌套属性实现INotifyPropertyChanged

llo*_*mas 15 c# wpf binding mvvm inotifypropertychanged

我有一个Person类:

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
}
Run Code Online (Sandbox Code Playgroud)

我有一个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
}
Run Code Online (Sandbox Code Playgroud)

我有一个ViewModel:

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

}
Run Code Online (Sandbox Code Playgroud)

我有一个视图,其中包含以下行:

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

<TextBox  Text="{Binding Person.Address.StreetOne, Mode=TwoWay,   
    UpdateSourceTrigger=PropertyChanged />
Run Code Online (Sandbox Code Playgroud)

视图加载时,两个值都显示在文本框中.

OnPropertyChanged( "Person" )在MyViewModel 中触发对第一个文本框的更改.大.

对MyViewModel内部的第二个文本框的更改("Person.Address.StreetOne")不会触发OnPropertyChanged( "Person" ).这意味着它不会调用Person对象的SET方法.不是很好.有趣的是,调用了Address类中的StreetOne的SET方法.

如何在Person.Address.StreetOne更改时调用ViewModel中的Person对象的SET方法?

我是否需要展平我的数据,以便SteetOne在Person内部而不是Address?

谢谢!

And*_*lon 15

虽然向ViewModel添加"传递"属性是一个很好的解决方案,但它很快就会变得难以维持.标准替代方法是传播更改,如下所示:

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

             _primaryAddress = value;

             if (_primaryAddress != null)
               _primaryAddress.PropertyChanged += AddressChanged;

             OnPropertyChanged( "PrimaryAddress" );
           }

           void AddressChanged(object sender, PropertyChangedEventArgs args) 
               => OnPropertyChanged("PrimaryAddress");
        }
  }
Run Code Online (Sandbox Code Playgroud)

现在,更改通知将从地址传播到人员.

编辑:将处理程序移动到c#7本地函数.


bli*_*eis 9

如果要调用viewmodel SET,可以创建一个street属性

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

 }
Run Code Online (Sandbox Code Playgroud)

XAML

<TextBox  Text="{Binding Street, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged />
Run Code Online (Sandbox Code Playgroud)

但这种解决方案有其缺点.我在我的项目中与Reeds一起回答


Ree*_*sey 5

当Person.Address.StreetOne更改时,如何获取ViewModel内部的Person对象的SET方法?

为什么要这样做?它不是必需的-您只需要StreetOne触发属性更改事件即可。

我是否需要拼合数据,以便SteetOne位于Person内部而不是Address?

如果您想实际触发该事件,则无需使其变平(尽管这是一个选择)。您可以在Person类中订阅AddressPropertyChanged事件,并在Person更改时在“ Address”事件中引发该事件。但是,这不是必需的。