Difference between Set() and RaisePropertyChanged(

2020-08-05 11:21发布

问题:

I am reading this http://msdn.microsoft.com/en-us/magazine/jj651572.aspx to learn mvvm light framework. I download the source code Friend.cs.

My question is why some set method of different property are implemented differently.

For example, the setter for First name is, why I need 'ref' keyword for _firstName.

 Set(FirstNamePropertyName, ref _firstName, value);

And the setter for DateOfBirthString is "

RaisePropertyChanged(() => DateOfBirth);

When will the linq expression will be evaluated?

namespace MyFriends.Model
{
    [SimpleSerialize]
    public class Friend : ObservableObject
    {
        /// <summary>
        /// The <see cref="FirstName" /> property's name.
        /// </summary>
        public const string FirstNamePropertyName = "FirstName";

        private string _firstName;

        /// <summary>
        /// Sets and gets the FirstName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        [SimpleSerialize(FieldName = "first_name")]
        public string FirstName
        {
            get
            {
                return _firstName;
            }
            set
            {
                Set(FirstNamePropertyName, ref _firstName, value);
            }
        }

        /// <summary>
        /// The <see cref="LastName" /> property's name.
        /// </summary>
        public const string LastNamePropertyName = "LastName";

        private string _lastName;

        /// <summary>
        /// Sets and gets the LastName property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        [SimpleSerialize(FieldName = "last_name")]
        public string LastName
        {
            get
            {
                return _lastName;
            }
            set
            {
                Set(LastNamePropertyName, ref _lastName, value);
            }
        }

        /// <summary>
        /// The <see cref="DateOfBirth" /> property's name.
        /// </summary>
        public const string DateOfBirthPropertyName = "DateOfBirth";

        private string _dateOfBirthString;

        /// <summary>
        /// Sets and gets the DateOfBirth property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        [SimpleSerialize(FieldName = "birthday")]
        public string DateOfBirthString
        {
            get
            {
                return _dateOfBirthString;
            }
            set
            {
                _dateOfBirthString = value;
                RaisePropertyChanged(() => DateOfBirth);
            }
        }

        public DateTime DateOfBirth
        {
            get
            {
                if (string.IsNullOrEmpty(_dateOfBirthString))
                {
                    return DateTime.MinValue;
                }

                return DateTime.ParseExact(DateOfBirthString, "d", CultureInfo.InvariantCulture);
            }
            set
            {
                _dateOfBirthString = value.ToString("d", CultureInfo.InvariantCulture);
            }
        }

        private string _imageUrl;

        [SimpleSerialize(FieldName = "picture")]
        public string ImageUrl
        {
            get
            {
                return _imageUrl;
            }
            set
            {
                _imageUrl = value;
                RaisePropertyChanged(() => ImageUri);
            }
        }

        public Uri ImageUri
        {
            get
            {
                return new Uri(_imageUrl);
            }
        }
    }
}

回答1:

The difference between those two methods is that the Set method replaces the old value of the _firstName field and then raises the PropertyChanged event, while the RaisePropertyChanged only raises the PropertyChanged event.

You'll want to use the Set method in most cases, since it helps to shorten property declarations by wrapping all that typically needs to be done within a property's setter in just one method:

  1. It updates the value of the passed field and overwrites it with the content of value, and then
  2. raises the PropertyChanged event to notify Views about this update.

The reason the field needs to be passed by reference (thus using ref _firstName) is that not the field's content is needed within the Set method, but the field itself is actually updated.

The RaisePropertyChanged method is useful when an update of one property does also affect additional properties. In this case, these properties' contents need to be updated manually, then the RaisePropertyChanged method can be called to inform Views about which properties have actually changed.



回答2:

One instance I found that Set(ref _prop, value) doesn't work is when you need to resend an update or need to do a custom comparison. Set(ref _prop, value) will do a compare on the _prop and value for you but it may not be what you want. For some properties i may want to add some more conditions beyond just a comparison in which case I'll set the _prop = value manually and then raise the change right after;

But in most cases I use the Set(ref _prop, value)



回答3:

Here is an actual usage, where the IsRunning is the primary operation, but it also raises a change notification on the property IsComplete which is based on IsRunning. This way both properties send a notify without undo extra coding.

private bool _IsRunning;

public bool IsRunning
{
    get => _IsRunning;
    set
    {
        SetProperty(ref _IsRunning, value);
        RaisePropertyChanged("IsComplete");
    }
}

public bool IsComplete => !IsRunning;