using a Code Snippet for INotifyPropertyChanged

前端 未结 5 597
再見小時候
再見小時候 2020-12-17 23:46

I found this code snippet for INotifyPropertyChanged

But it shows the code like this :

\"INotifyProperty

5条回答
  •  无人及你
    2020-12-18 00:26

    I'm going to give you the answer you don't want to hear: You shouldn't need to do this at all. Your model should have the (full or auto) properties, and then your ViewModel properties should just have a getter and a setter that returns _model.MyProperty.

    Also, you may want to look into CallerMemberName to get rid of that pesky magic string. I'll post some examples if you want me to.


    For example, I have a DealsUser model class (note how internal logic like generating the email address if it was never explicitly set, is done here):

    public class DealsUser : IDealsUser
    {
        public DealsUser() : this("GUEST")
        {
        }
    
        public DealsUser(string username)
        {
            this.Username = username;
            this.IsAdministrator = false;
            this.IsPlanModerator = false;
            this.IsPlanner = false;
        }
    
        public string Username { get; set; }
    
        public bool IsAdministrator { get; set; }
    
        public bool IsPlanModerator { get; set; }
    
        public bool IsPlanner { get; set; }
    
        private string _emailAddress;
        public string EmailAddress
        {
            get
            {
                return _emailAddress ?? string.Format(
                    "{0}@mycompany.co.za", this.Username);
            }
            set
            {
                _emailAddress = value;
            }
        }
    
        public override string ToString()
        {
            return this.Username;
        }
    

    And I have a BaseViewModel class with the following event and protected methods (note how we use CallerMemberName to eliminate magic strings):

    #region INotifyPropertyChanged Members
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    protected bool SetProperty(ref T storage, T value,
        [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value))
        {
            return false;
        }
    
        storage = value;
        this.OnPropertyChanged(propertyName);
        return true;
    }
    
    protected bool SetModelProperty(T storage, T value, Action setter,
        [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(storage, value))
        {
            return false;
        }
    
        setter();
        this.OnPropertyChanged(propertyName);
        return true;
    }
    
    #endregion
    

    I then inherit from BaseViewModel, I dependency inject the model into my constructor, and I try to keep my ViewModel as lean as possible. Note that I have to use SetModelProperty instead of SetProperty, because you cannot pass a property (e.g. _dealsUser.Username) into a lamba function as a reference variable. Also note that IsPlanner and IsPlanModerator contain extra logic that updates related notifying properties when they change:

    public class DealsUserVM : BaseViewModel
    {
        private readonly IDealsUser _dealsUser;
    
        public DealsUserVM()
            : this(new DealsUser())
        {
            // Empty ctor
        }
    
        public DealsUserVM(IDealsUser dealsUser)
        {
            _dealsUser = dealsUser;
        }
    
        public IDealsUser Model
        {
            get
            {
                return _dealsUser;
            }
        }
    
        public string Username
        {
            get { return _dealsUser.Username; }
            set
            {
                SetModelProperty(_dealsUser.Username, value,
                    () => { _dealsUser.Username = value; });
            }
        }
    
        public bool IsAdministrator
        {
            get { return _dealsUser.IsAdministrator; }
            set
            {
                SetModelProperty(_dealsUser.IsAdministrator, value,
                    () => { _dealsUser.IsAdministrator = value; });
            }
        }
    
        public bool IsPlanModerator
        {
            get { return _dealsUser.IsPlanModerator; }
            set
            {
                // If IsPlanModerator has changed (and was updated as a result)
                if (SetModelProperty(_dealsUser.IsPlanModerator, value,
                    () => { _dealsUser.IsPlanModerator = value; }))
                {
                    // If IsPlanModerator is now TRUE
                    if (value)
                    {
                        this.IsPlanner = true;
                    }
                }
            }
        }
    
        public bool IsPlanner
        {
            get { return _dealsUser.IsPlanner; }
            set
            {
                // If IsPlanner has changed (and was updated as a result)
                if (SetModelProperty(_dealsUser.IsPlanner, value,
                        () => { _dealsUser.IsPlanner = value; }))
                {
                    // If IsPlanner is now FALSE
                    if (!value)
                    {
                        this.IsPlanModerator = false;
                    }
                }
            }
        }
    
        public string EmailAddress
        {
            get { return _dealsUser.EmailAddress; }
            set
            {
                SetModelProperty(_dealsUser.EmailAddress, value,
                    () => { _dealsUser.EmailAddress = value; });
            }
        }
    
        public override string ToString()
        {
            return _dealsUser.ToString();
        }
    }
    

    Hope this helps :-)

提交回复
热议问题