9

I was reading about the new nameof keyword in C# 6. I want to know how can I implement INotifyPropertyChanged using this keyword, what are the prerequisites (of course other than C# 6) and how it will effect the performance of my MVVM application?

Mehrad
  • 4,093
  • 4
  • 43
  • 61
  • 1
    There are already alternatives to the magic string problem, just so you know. Though `nameof` should formalise that. – Adam Houldsworth Dec 12 '14 at 11:18
  • 1
    No, I never pointed that out. I was merely informing you just in case you were waiting for something that is not yet released to solve something that you could solve today. It is also useful for *other* visitors as this question is not solely for your benefit. – Adam Houldsworth Dec 12 '14 at 11:22
  • Useful _RegEx_ to replace all in _Visual Studio_: from `OnPropertyChanged("(?\w+)"\);` to `OnPropertyChanged(nameof(${propName}));` – itsho May 03 '21 at 08:13

5 Answers5

14

It would look like this:

public string Foo
{
   get
   {
      return this.foo;
   }
   set
   {
       if (value != this.foo)
       {
          this.foo = value;
          OnPropertyChanged(nameof(Foo));
       }
   }
}

The nameof(Foo) will be substituted with the "Foo" string at compile time, so it should be very performant. This is not reflection.

Wim Coenen
  • 66,094
  • 13
  • 157
  • 251
  • Which ironically is *more* code than the other mechanism that uses `CallerMemberName`, and unfortunately is not as comical as `infoof`. – Adam Houldsworth Dec 12 '14 at 11:20
  • 2
    `CallerMemberName` is only available in .NET 4.5. `Nameof` comes with the C# compiler so you'll still be able to target older .NET frameworks. – Wim Coenen Dec 12 '14 at 11:24
  • True, hadn't thought of that benefit. But interestingly, `CallerMemberName` is also a [compiler-powered feature](http://stackoverflow.com/questions/13381917/is-the-callermembername-attribute-in-4-5-able-to-be-faked) so can be taken out of the .NET 4.5 dependency. I would personally change to `nameof` for the other reason that the code is more explicit and less is hidden from the caller's perspective. – Adam Houldsworth Dec 12 '14 at 11:24
  • I suppose `nameof(Foo)` is enough since the property is certainly in scope. If you want to qualify for some reason, isn't `nameof(this.Foo)` better than `nameof(MyClass.Foo)` for a non-static member? I have not tried to actually compile any of this. – Jeppe Stig Nielsen Dec 12 '14 at 17:09
  • I still believe that `[CallerMemberName]` has the advantage simply because `nameof` doesn't solve the pedanticity (?) problem, i.e. you still have to write the enclosing property's name manually in each property. At that point you might as well just type a magic string there. Whereas `[CallerMemberName]` is less human-error-prone because you write the same line of code in each and the compiler takes care of getting the correct property name. – nam20485 Aug 05 '23 at 19:38
6

It's just a matter of using nameof() instead of the magic string. The example below is from my blog article on the subject:

private string currentTime;

public string CurrentTime
{
    get
    {
        return this.currentTime;
    }
    set
    {
        this.currentTime = value;
        this.OnPropertyChanged(nameof(CurrentTime));
    }
}

Since it is evaluated at compile-time, it is more performant than any of the current alternatives (which are also mentioned in the blog article).

Community
  • 1
  • 1
Gigi
  • 28,163
  • 29
  • 106
  • 188
4

Here's a complete code sample of a class using the new C# 6.0 sugar:

public class ServerViewModel : INotifyPropertyChanged {
    private string _server;
    public string Server {
        get { return _server; }
        set {
            _server = value;
            OnPropertyChanged(nameof(Server));
        }
    }

    private int _port;
    public int Port {
        get { return _port; }
        set {
            _port = value;
            OnPropertyChanged(nameof(Port));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName) => 
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

With this, you get the nameof() operator, the null-conditional operator ?., and an expression-bodied function (the OnPropertyChanged definition).

saluce
  • 13,035
  • 3
  • 50
  • 67
3

I've found it's a lot easier to use PropertyChanged.Fody as you end up with less mistakes and a hell of a lot cleaner code, see - https://github.com/Fody/PropertyChanged

All you have to do is label up your class with ImplementPropertyChanged attribute:

[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

And after build it gets transformed in to:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Kevin Smith
  • 13,746
  • 4
  • 52
  • 77
  • Fantastic helper. I use a lot of POCOs for data interchange with ServiceStack, and this lets me keep them super-simple (code-wise). – jklemmack Mar 02 '16 at 17:11
  • This answer would be better if you included an explanation of what Fody is. Also, the transformed code still has magic strings in it, which is what the OP wants to avoid. If the name of one of the properties is changed, will Fody update the strings automatically too? – kmote Jan 19 '17 at 20:02
  • So fody is a post build il weaver so it changes your code after its built... The magic strings will get updated automatically after each build – Kevin Smith Jan 19 '17 at 20:04
1

See the documentation for INotifyPropertyChanged.PropertyChanged Event

private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
Leo S
  • 11
  • 2