Get notified when properties change in the Model

后端 未结 4 853
-上瘾入骨i
-上瘾入骨i 2021-01-27 05:16

There seems to be conflicting thoughts on whether INotifyPropertyChanged should be implemented in the Model or not. I think that it should be implemented in the Vie

相关标签:
4条回答
  • 2021-01-27 05:45

    Interesting question. I've read about MVVM for more than a year now, and I'm still not sure about it.

    If your application is representing a state of a process for example, and this state is modified internally without any interaction of the user, then your model needs to be able to notify your viewmodel that it changed. So if your model implement INotifyPropertyChanged, and your viewmodel only pass the same informations to the view, then... does your viewmodel really need to exist...?

    In our company, we consider two main cases:

    • We structure our software with a quite strict UML analysis before developping (not so agile). When we then want to display our objects on screen, they return us their different views, which are used when needed with Bindings (using ContentControl or so). Most of the views we need for our software display these kinds of object, that implement INotifyPropertyChanged and are therefore also kind of ViewModels.

    • To build the software main Views (view structure), we create global views and ViewModels for them. That's when we really follow the MVVM practices.

    Maybe I missed a point about MVVM, but in my experience, it's not a pattern that you absolutely have to always follow. It's a very good way of thinking to develop WPF applications, but creating ViewModels for each and every view seems to me like a big overhead.

    What do all of you think of this way of doing?

    Best regards,

    Antoine

    EDIT 31.03.2012

    I have found a very interesting article explaining how to handle your model properties in the viewmodel, without having to implement a proxy property in the viewModel for each one of them. Also the writer say some words about having INPC implemented in the model, and the viewmodel listening to it. I think this is the most practical oriented article I've read about MVVM so far. Check it out : http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

    0 讨论(0)
  • 2021-01-27 05:47

    Save for the typos you pretty much have it ;)

    All you would need to add is your constructor and property definitions:

    public class PersonViewModel : INotifyPropertyChanged
    {
        Person _person;
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected virtual void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
    
        public PersonViewModel(Person person)
        {
            _person = person;
        }
    
        public int Age
        {
            get
            {
                return _person.Age;
            }
            set
            {
                _person.Age = value;
                OnPropertyChanged("Age");
            }
        }
    }
    

    If you have a choice, I would definitely recommend implementing INotifyPropertyChanged in the Model because you won't havae to worry about translating Models to ViewModels and back.

    But if you can't, see above :)

    0 讨论(0)
  • 2021-01-27 05:50

    In my experience, Model objects don't have to (and probably shouldn't) know that they are being constructed in a View. Often, Model objects are entities that should never be allowed to be in an invalid state. ViewModel objects are the things that construct the Model objects.

    So, since you never want to create a person who is very old or very young, and every person needs a name, your Person class might look like this:

    public class Person {
        public int Age { get; private set; }
        public string Name { get; private set; }
        public Person(int age, string name) {
            if (age < 0 || age > 150) throw new ArgumentOutOfRangeException();
            if (string.IsNullOrEmpty(name)) throw new ArgumentNullException();
            Age = age;
            Name = name;
        }
    }
    

    And your PersonViewModel might look like this::

    class PersonViewModel : INotifyPropertyChanged {
        private int _Age;
        private int _Name;
        public int Age {
            get { return _Age; }
            set {
                if (_Age.Equals(value)) return;
                _Age = value;
                RaisePropertyChanged("Age");
            }
        }
        public string Name {
            get { return _Name; }
            set {
                if (_Name.Equals(value)) return;
                _Name = value;
                RaisePropertyChanged("Name");
            }
        }
        public Person CreatePerson() {
            return new Person(_Age, _Name);
        }
    }
    

    You can then put whatever values you want in your PersonViewModel without worrying about creating an invalid Person object. You can also implement validation in the PersonViewModel that may be more strict than the validation in the Person class (for example, restricting the age range to adults over 18 years old (see IDataErrorInfo)).

    0 讨论(0)
  • 2021-01-27 05:54

    ViewModel should definitely implement INotifyPropertyChanged. I don't have a strong opinion on whether it should be implemented in the Model as well. I don't think you need it when the model properties don't change independently from the ViewModel while it is bound to the View.

    Anyway, this is how I'd implement INotifyPropertyChanged in the ViewModel when it is not already implemented in the Model:

    public class PersonViewModel : INotifyPropertyChanged 
    {
        private Person person;
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName) 
        {
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    
        public PersonViewModel(Person person)
        {
            this.person = person;
        }
    
        public int Age
        {
            get { return person.Age; }
            set
            {
                if (value != person.Age)
                {
                    person.Age = value;
                    OnPropertyChanged("Age");
                }
            }
        }
    
        public string FirstName
        {
            get { return person.FirstName; }
            set
            {
                if (value != person.FirstName)
                {
                    person.FirstName = value;
                    OnPropertyChanged("FirstName");
                }
            }
        }
    
        public string LastName
        {
            get { return person.LastName; }
            set
            {
                if (value != person.LastName)
                {
                    person.LastName = value;
                    OnPropertyChanged("LastName");
                }
            }
        }
    }
    

    Seeing how you updated you question, I need to add that without having INotifyPropertyChanged (or a similar custom notification event) implemented in the model, you can't get notified about the changes in the model that happen in it independently from the ViewModel. I guess you should be able to avoid that. Otherwise just implement INotifyPropertyChanged in it. There's nothing wrong with that if you need it.

    0 讨论(0)
提交回复
热议问题