Получать уведомления при изменении свойств в модели - PullRequest
0 голосов
/ 29 марта 2012

Похоже, существуют противоречивые мысли о том, должен ли INotifyPropertyChanged быть реализован в модели или нет.Я думаю, что это должно быть реализовано во ViewModel, но я не могу понять, как это будет достигнуто.Есть много упоминаний об этой же идее во всем stackoverlow.com ( В модели MVVM должна ли модель реализовывать интерфейс INotifyPropertyChanged? , В MVVM должна ли ViewModel или Model реализовывать INotifyPropertyChanged? )но я не могу найти ни одного примера, чтобы показать, как это сделать.

Скажем, например, у меня есть модель Person:

Public Person {
  public int Age { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public void NameChange( string newName );
}

Как мне реализовать ViewModel, чтобы изменения вAge, FirstName или LastName все распознаны?

Public PersonViewModel : INotifyPropertyChanged {
  Person _person;
  public event PropertyChangedEventHandler PropertyChanged;
  void OnPropertyChanged(string propertyName) {
    if(this.PropertyChanged != null)
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
  //ctor, Properties, etc...
}

РЕДАКТИРОВАТЬ - Уточнение:

Итак без изменения модели Person как мне изменить ViewModel, чтобы получать уведомления об обновлениях?

Это вообще возможно?Если нет, то как те, кто подписан на «INPC в модели - это baaaad », получают уведомления об изменениях в модели?

Ответы [ 4 ]

2 голосов
/ 29 марта 2012

ViewModel должен обязательно реализовывать INotifyPropertyChanged. У меня нет четкого мнения о том, должно ли это быть реализовано и в модели. Я не думаю, что вам это нужно, когда свойства модели не изменяются независимо от ViewModel, пока он связан с View.

Во всяком случае, так я бы реализовал INotifyPropertyChanged во ViewModel, когда он еще не реализован в модели:

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");
            }
        }
    }
}

Видя, как вы обновили свой вопрос, мне нужно добавить, что без реализации INotifyPropertyChanged (или аналогичного пользовательского события уведомления) в модели вы не сможете получать уведомления об изменениях в модели, которые происходят в ней, независимо от ViewModel. Я полагаю, вы должны этого избежать. В противном случае просто реализуйте INotifyPropertyChanged в нем. В этом нет ничего плохого, если вам это нужно.

1 голос
/ 30 марта 2012

Интересный вопрос. Я читал о MVVM уже больше года, и до сих пор не уверен в этом.

Если ваше приложение, например, представляет состояние процесса, и это состояние изменяется внутренне без какого-либо взаимодействия с пользователем, тогда ваша модель должна иметь возможность уведомить вашу модель представления о том, что она изменилась. Поэтому, если ваша модель реализует INotifyPropertyChanged, и ваша модель представления передает только те же данные в представление, то ... действительно ли ваша модель представления должна существовать ...?

В нашей компании мы рассмотрим два основных случая:

  • Мы структурируем наше программное обеспечение с помощью довольно строгого анализа UML перед разработкой (не так быстро). Когда мы затем хотим отобразить наши объекты на экране, они возвращают нам свои различные представления, которые используются при необходимости с привязками (используя ContentControl или около того). Большинство представлений, которые нам нужны для нашего программного обеспечения, отображают объекты такого типа, которые реализуют INotifyPropertyChanged и, следовательно, также являются видами ViewModels.

  • Чтобы построить программное обеспечение основных видов (структура представления), мы создаем глобальные виды и модели для них. Именно тогда мы действительно следуем практикам MVVM.

Может быть, я упустил момент о MVVM, но по моему опыту, это не тот шаблон, которому вы всегда должны следовать. Это очень хороший способ думать о разработке приложений WPF, но создание ViewModel для каждого и каждого вида кажется мне большим расходом.

Что вы все думаете об этом способе?

С уважением,

Antoine

РЕДАКТИРОВАТЬ 31.03.2012

Я нашел очень интересную статью, объясняющую, как обрабатывать свойства вашей модели в viewmodel, без необходимости реализовывать свойство proxy в viewModel для каждого из них. Также автор говорит несколько слов о внедрении INPC в модель и о модели прослушивания. Я думаю, что это самая практичная статья, которую я когда-либо читал о MVVM. Проверьте это: http://msdn.microsoft.com/en-us/magazine/ff798279.aspx

0 голосов
/ 29 марта 2012

За исключением опечаток, которые у вас есть;)

Все, что вам нужно добавить, - это определения вашего конструктора и свойств:

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");
        }
    }
}

Если у вас есть выбор, я быопределенно рекомендую реализовать INotifyPropertyChanged в модели, потому что вам не придется беспокоиться о переводе моделей в ViewModels и обратно.

Но если вы не можете, см. выше:)

0 голосов
/ 29 марта 2012

По моему опыту, Model объекты не должны (и, вероятно, не должны) знать, что они создаются в View.Часто Model объекты - это объекты, которым никогда не разрешается находиться в недопустимом состоянии .ViewModel объекты - это вещи, которые создают Model объекты.

Итак, поскольку вы никогда не хотите создавать человека очень старого или очень молодого возраста, и каждому человеку нужно имя, ваше Personкласс может выглядеть следующим образом:

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;
    }
}

А ваш PersonViewModel может выглядеть следующим образом: *

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);
    }
}

Затем вы можете поместить любые значения в свой PersonViewModel, не беспокоясьо создании недопустимого объекта Person.Вы также можете реализовать проверку в PersonViewModel, которая может быть более строгой, чем проверка в классе Person (например, ограничение возрастного диапазона для взрослых старше 18 лет (см. IDataErrorInfo )).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...