I'm relatively new to MVVM and I'm trying to understand how INotifyPropertyChanged interface works and how to implement it in my models. The approach that I decided to take was to implement it in each of my Business Object classes.
The problem with that approach is that when I bind my View to a property in a Base class the PropertyChanged event in that base class never gets initialized (is null) and therefore the View does not refresh the data for that element when my Model changes. I was able to reproduce the problem with the example below.
I have a Person Base class:
public class Person : INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
private String _name;
}
And I have an Employee class inheriting from my Person Base class:
public class Employee : Person,INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String EmployeeID
{
get
{
return _employeeId;
}
set
{
_employeeId = value;
RaisePropertyChanged("EmployeeID");
}
}
private String _employeeId;
}
Here my View Model:
public class ViewModel : ViewModelBase<ViewModel>
{
private Employee _employee;
public ViewModel()
{
ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel);
Employee = new Employee()
{
Name = "BOB",EmployeeID = "1234"
};
}
public ICommand ChangeModelCommand { get; set; }
public Employee Employee
{
get
{
return _employee;
}
set
{
this._employee = value;
NotifyPropertyChanged(m=>m.Employee);
}
}
public void ChangeModel()
{
MessageBox.Show("CHANGING MODEL");
this.Employee.Name = "MIKE";
this.Employee.EmployeeID = "5678";
}
public bool CanChangeModel
{
get{ return true;}
}
}
And finally my View:
<Window.Resources>
<MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource Model}">
<StackPanel>
<Label Content="Employee Name"/>
<TextBox Text="{Binding Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Label Content="Employee ID"/>
<TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/>
</StackPanel>
</Grid>
In this example I initialize my Employee VM Property in the VM constructor and then I have a command to modify the EmployeeID (from Employee class) and Name (from Person Class). However, the only UI element in the View that gets updated is the EmployeeID and not the Name (I expected Bob to update to Mike).
While debugging I found that PropertyChanged event was always null in my base class (Person). I also noticed that when I remove the whole #INotifyProperty region from my Employee class everything works fine since it is using the Base Type event and methods.
The problem I have with that is that all my current model classes implement INotifyPropertyChanged explicitly. They all define a PropertyChanged event and implement the RaisePropertyChanged method, which obviously will impact my bindings in my MVVM application.
Lastly, I want to clarify that I do not want wrap my Model properties in my ViewModel and rely on the VM INPC mechanism. I would like to use my Model INPC implementation already in place whithout having to conditionally remove the INPC implementations depending on whether I am inheriting or not from a base type.
In summary, I would like to know what's the best way to implement the INPC in my deeply hierarchical model so that inheritance doesn't break the PropertyEvent propagation as we saw in this example and so my independent classes can be self sufficient as well. Any ideas or suggestions will be greatly appreciated :)