1

I want to raise PropertyChanged event for a model with DataContract. Initially I did this

[DataContract]
public partial class User : INotifyPropertyChanged
{
    [DataMember(Name="username")]
    public string Username
    {
        get
        {
            return this.Username;
        }
        set
        {
            this.Username = value;
            RaisePropertyChanged("Username");
        }
    }
}

which gave StackOverflow Exception beacause of Infinite Recursion.

So the solution I come up with is

[DataContract]
public partial class User : INotifyPropertyChanged
{
    private string _Username { get; set; }
    [DataMember(Name="username")]
    public string Username
    {
        get
        {
            return this._Username;
        }
        set
        {
            this._Username = value;
            RaisePropertyChanged("Username");
        }
    }
}

Although this reflects the Username value to the control binding to "Username", this doesn't look the best way to me. Something is wrong. Also my model has approx 30-40 fields. Is this the right approach or can someone please suggest me a better way.

Thanks

pratpor
  • 1,954
  • 1
  • 27
  • 46
  • That is generally the right way. Yes, there are slightly fancier ways of raising notifications, but what you've done will work fine for now. You can get rid of the `this.` in front of the private member assignment. http://stackoverflow.com/a/13720780/109702 – slugster Aug 21 '14 at 12:42
  • There's no need for `_Username` to be a property; that should be a field. – Marc Gravell Aug 21 '14 at 12:45

2 Answers2

3

I'd be so tempted to use caller-member-name here (if it is in your target framework):

private string _username;
[DataMember(Name="username")]
public string Username
{
    get { return _username; }
    set { SetField(ref _username, value); }
}

private void SetField<T>(ref T field, T value,
    [CallerMemberName] string memberName = null)
{
    if(!EqualityComparer<T>.Default.Equals(field,value))
    {
        field = value;
        RaisePropertyChanged(memberName);
    }
}

If caller-member-name isn't supported:

[DataMember(Name="username")]
public string Username
{
    get { return this._Username; }
    set { SetField(ref _Username, value, "Username"); }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks. [CallerMemberName] isn't supported in windows-phone. – pratpor Aug 21 '14 at 13:01
  • 2
    @PratPor that actually depends on what compiler you're using; since it is **entirely** a compiler feature (not a framework feature), you can actually declare the attribute yourself (in the right namespace etc) - if you are using an up-to-date compiler, *it will work* – Marc Gravell Aug 21 '14 at 13:06
2
[DataContract]
public partial class User : INotifyPropertyChanged
{
    private string _Username;

    [DataMember(Name="username")]
    public string Username
    {
        get
        {
            return this._Username;
        }
        set
        {
            if(this._Username != value)
            {
                this._Username = value;
                RaisePropertyChanged("Username");
            }
        }
    }
}
ajg
  • 1,743
  • 12
  • 14