Wednesday, December 11, 2013

INotifyPropertyChanged Without Hardcoding the Property Name

If you are doing WPF or Silverlight using MVVM pattern, I am pretty sure your ViewModel is implementing INotifyPropertyChanged. Basically what INotifyPropertyChanged does is it notifies it’s clients when the value of a property (which a client is listening in) has changed.

Let’s go by an example. I have created a very simple WPF Aplictaion and I have the following Employee View Model which implements INotifyPropertyChanged. There are two properties which are the FirstName and the LastName which raises NotifyPropertyChanged() when values of the properties are changed.
public class EmployeeViewModel:INotifyPropertyChanged
{
   private string firstName;
   public string FirstName
   {
       get
       {
           return firstName;
       }
       set
       {
           firstName = value;
           NotifyPropertyChanged("FirstName");
       }
   }
 
   private string lastName;
   public string LastName
   {
       get
       {
           return lastName;
       }
       set
       {
           lastName = value;
           NotifyPropertyChanged("LastName");
       }
   } 

   public event PropertyChangedEventHandler PropertyChanged;
   private void NotifyPropertyChanged(string propertyName)
   {
       if (PropertyChanged != null)
       {
           PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       }
   }
}
As you can see here, in the Setter of every property I am calling NotifyPropertyChanged passing the property name hard coded. And this is the part where my code looks ugly and there were hundreds of times I wanted to stop property name from hard coding. But for now lets keep it going this way. 

In my MainWindow.xaml I have following Stack Panel. I have two text boxes which are bound to FirstName and LastName properties of EmployeeViewModel. I have a button which will trigger a value change in the FirstName and LastName properties.
<StackPanel>
    <TextBox Text="{Binding FirstName}"></TextBox>
    <TextBox Text="{Binding LastName}"></TextBox>
    <Button Content="Button" Click="Button_Click"/>
</StackPanel>
In the MainWindow.xaml.cs I have the following code. I am setting up the current DataContext to EmployeeViewModel.
public partial class MainWindow : Window
{
    EmployeeViewModel employee = new EmployeeViewModel()
    {
        FirstName = "Jaliya",
        LastName = "Udagedara"
    }; 

    public MainWindow()
    {
        InitializeComponent();
        DataContext = employee;
    }
 
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        employee.FirstName = "John";
        employee.LastName = "Smith";
    }
}
If I run this simple application I am getting the expected result. Which is initially text boxes will be filled with values “Jaliya” and “Udagedara”. Once I click on the button property values will be changed to "John" and "Smith" and will be reflected in the text boxes. To make this happen in my EmployeeViewModel, in the property Setters I have hardcoded property names. So when ever the property values get changed, they will say "hey, I am FirstName property and my value just got changed!".  My requirement now is, the property should not specifically pass it's property name when it raises NotifyPropertyChanged().

With the C# 5 or with .NET Framework 4.5 and above there is a nice feature which comes handy in these kind of scenartios. You can use Caller Information feature which will provide Caller Info attributes and using these you can obtain information about the caller to a method. So let me modify the code above as follows.
public class EmployeeViewModel:INotifyPropertyChanged
{
    private string firstName;
    public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            firstName = value;
            NotifyPropertyChanged();
        }
    }
 
    private string lastName;
    public string LastName
    {
        get
        {
            return lastName;
        }
        set
        {
            lastName = value;
            NotifyPropertyChanged();
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
If you can see here, I haven’t hard coded the Property Name when raising NotifyPropertyChanged() method. The compiler will fill in the information for me. If I debug and check the value of variable "propertyName", I can see the name of the property which is triggering the NotifyPropertyChanged().

Hope this helps. Please find the sample project in my SkyDrive.


Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment