How to implement INotifyPropertyChanged with nameof rather than magic strings?
Asked Answered
P

5

10

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?

Padua answered 12/12, 2014 at 11:14 Comment(3)
There are already alternatives to the magic string problem, just so you know. Though nameof should formalise that.Accrue
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.Accrue
Useful RegEx to replace all in Visual Studio: from OnPropertyChanged("(?<propName>\w+)"\); to OnPropertyChanged(nameof(${propName}));Ruthven
C
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.

Caster answered 12/12, 2014 at 11:18 Comment(5)
Which ironically is more code than the other mechanism that uses CallerMemberName, and unfortunately is not as comical as infoof.Accrue
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.Caster
True, hadn't thought of that benefit. But interestingly, CallerMemberName is also a compiler-powered feature 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.Accrue
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.Leadsman
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.Toneytong
F
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).

Fourpenny answered 13/12, 2014 at 9:30 Comment(1)
Thanks for the answer. I really liked your blog entryPadua
H
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).

Hurling answered 28/10, 2015 at 20:18 Comment(0)
A
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));
        }
    }
}
Antimissile answered 28/10, 2015 at 20:32 Comment(3)
Fantastic helper. I use a lot of POCOs for data interchange with ServiceStack, and this lets me keep them super-simple (code-wise).Baillieu
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?Holms
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 buildAntimissile
S
1

See the documentation for INotifyPropertyChanged.PropertyChanged Event

private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
Sinclare answered 7/10, 2019 at 5:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.