3

I was never sure about the meaning of propertyName when implementing INotifyPropertyChanged. So generally you implement INotifyPropertyChanged as:

public class Data : INotifyPropertyChanged {
   public event PropertyChangedEventHandler PropertyChanged;

   private void NotifyPropertyChanged(string propertyName = "") {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

   private string itsID;
   public string ID { 
             get { return itsID; }
             set { 
                   if (itsID != value) {
                     itsID = value; 
                     NotifyPropertyChanged("ID");
                  }
   }
}

I was never sure about the propertyName argument to NotifyPropertyChanged(string propertyName).

  1. Can that be any arbitrary string (like "MyID" in the above example)?
  2. Or does .NET use Reflection to align it with a property in a class so it has to match the name of the property exactly?
  3. What if the propertyName doesn't match the name of the Property exactly, does .NET consider the entire object as changed?
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
Denis
  • 11,796
  • 16
  • 88
  • 150
  • Just a safety note: when you're doing `if (PropertyChanged != null)` try and avoid this, as it is possible that after the `null` check `PropertyChanged` might indeed be `null` again. Instead, it is safer/better practise to set a local variable first, then check. e.g. `var handler = PropertyChanged; if (handler != null) { handler()... // raise }` - or from C#6, you can use the new "null conditional operator": `PropertyChanged?.Invoke(...)` which doubles up as a `null` check *and* invoke at once. – Geoff James Oct 20 '16 at 19:50
  • 2
    Its explained pretty well here (https://www.cs.colorado.edu/~kena/classes/5448/f12/presentation-materials/ellis.pdf) and I think this is the .NET source code that does perform the actual tracking of all of these (https://referencesource.microsoft.com/#System.Data.Services.Client/Client/System/Data/Services/Client/Binding/BindingObserver.cs,2ac792c61e2e7eb2,references). WPF basically subscribes to property change events and then makes use of the event arguments, one of which is the string you use for the ID, like, `MyID`, and then makes use of that to do the update on the control. – Alexandru Oct 20 '16 at 20:10

4 Answers4

2

If you want to match the name of the property exactly, you can use the new C#6 feature called nameof. The nameof feature is answers all of your questions because we could say the main advantage of using nameof in one word is refactoring. And "refactoring" is the word that you are looking for based on your questions:

NotifyPropertyChanged(nameof(ID));

As an example renaming ID will change the name of the property too, or it will break compilation but the following doesn't:

NotifyPropertyChanged("ID")
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
  • C# 6 doesn't add much there: C# 5 already provided the `[CallerMemberName]` attribute. `NotifyPropertyChanged();` leaves even less room for typos. That said, this should be a comment, it doesn't try to answer the question. –  Oct 20 '16 at 19:41
  • 1
    @hvd Yes. But the most use case of `nameof` for me is when working with the `INotifyPropertyChanged` interface. – Salah Akbari Oct 20 '16 at 19:43
  • 1
    @hvd This does add a lot, actually. You can link data more effectively now. Just right click and find all references when using `nameof`. Much better than this `CallerMemberName`. – Alexandru Oct 20 '16 at 19:46
  • @Alexandru `nameof` certainly has its uses, but we're talking about a reference inside the property setter here. You'd already have found that without any IDE feature. –  Oct 20 '16 at 19:48
  • @hvd Yeah, but cases for `NotifyPropertyChanged` also exist outside of property setters, themselves, which `nameof` would be able to handle for the developer. Its just less to worry about, and more organization, and that's what I like. – Alexandru Oct 20 '16 at 19:55
  • @Alexandru Sure, agreed, `nameof` is useful, just not in the context of this question, which is about the property setters. I certainly hope this answer was intended in the context of the question. –  Oct 20 '16 at 19:58
  • @hvd The `nameof` feature answers all three OP's questions. Because we could say the main advantage of using `nameof` in one word is **refactoring**. I think "refactoring" is the point that OP is looking for based on his questions at the end of his post. – Salah Akbari Oct 20 '16 at 20:02
  • @hvd I agree, primarily OP is looking to find out how this all works internally so I posted a comment to the relevant .NET code. Other than that, he should use `nameof`. :) – Alexandru Oct 20 '16 at 20:43
2

It's not .NET Framework itself per se, it's pretty much every PropertyChanged subscriber out there (some of which do indeed happen to be distributed as part of the framework) that assumes you use the interface as intended, by sending the property name. If you send a notification that the property MyID has changed, when another component is looking at the property ID, it will typically see the notification, compare the names, and conclude "this notification isn't for me".

1

It has to match the name of the property exactly. On a side note, you should check that the value has actually changed before calling PropertyChanged since that is a relatively expensive call (WPF would not know the property has not changed). In VS2015, you can also use the nameof operator.

SledgeHammer
  • 7,338
  • 6
  • 41
  • 86
0

According to the INotifyPropertyChanged Interface page, you can leave the propertyName parameter undefined. Here's why:

// This method is called by the Set accessor of each property.  
// The CallerMemberName attribute that is applied to the optional propertyName  
// parameter causes the property name of the caller to be substituted as an argument.  
private void NotifyPropertyChanged([CallerMemberName] String 
        propertyName = "")  
{  
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}  

Notice the [CallerMemberName] attribute in the parameter. That will automatically substitute the name of the property in for the string, no need to define it statically. The documentation also specifies:

The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs. Note that in a UWP application, String.Empty must be used rather than null.

This is all just convenience for you to manually handle changes for specific controls, or the entire form. The INotifyPropertyChanged Interface doesn't define the NotifyPropertyChanged method, so one would have to know about the CallerMemberName attribute beforehand.

gcode
  • 2,954
  • 4
  • 21
  • 32