WPF MVVM INotifyPropertyChanged Implementation – модель или ViewModel

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

Я использую эту реализацию ObservableDictionary ( ObservableDictionary ), потому что мне нужны исполняемые запросы с использованием ключа.

В этом словаре я помещаю коллекцию объектов модели.

В моей виртуальной машине я объявляю экземпляр (Книги) словаря и привязываю его к XAML.

      

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

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

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

Событие «Изменено» не запускается в первом случае, потому что установщик словаря не вызывается, это элемент (книга).

Я что-то пропустил, потому что, если это правильная интерпретация, если я хочу получать последовательные уведомления для своих моделей независимо от того, связаны ли они непосредственно с XAML или с помощью какой-то коллекции, я всегда хотел, чтобы модель реализовала INotifyProperyChanged.

Кстати, помимо ссылки dll, я лично не вижу INotifyPropertyChanged как функцию пользовательского интерфейса – думаю, что ее нужно определить в более общем пространстве имен .net – мои 2 цента.

ИЗМЕНИТЬ ЗДЕСЬ:

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

Модели:

 public class Book { public string Title { get; set; ) public List Authors { get; set; } } public class Author { public string Name { get; set; } } 

Поставщик данных для создания некоторых фиктивных данных

 public class BookProvider { public ObservableCollection GetBooks() { ObservableCollection books = new ObservableCollection(); books.Add(new Book { Title = "Book1", Authors = new List { new Author { Name = "Joe" }, new Author { Name = "Phil" } } }); books.Add(new Book { Title = "Book2", Authors = new List { new Author { Name = "Jane" }, new Author { Name = "Bob" } } }); return books; } } 

ViewModel

  public class BookViewModel : INotifyPropertyChanged { private ObservableCollection books; public ObservableCollection Books { get { return books; } set { if (value != books) { books = value; NotifyPropertyChanged("Books"); } } } private BookProvider provider; public BookViewModel() { provider = new BookProvider(); Books = provider.GetBooks(); } // For testing the example public void MakeChange() { Books[0].Title = "Changed"; } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } } 

Код XAML позади Не было бы нормально для него таким образом – просто для простого примера

 public partial class MainWindow : Window { private BookViewModel vm; public MainWindow() { InitializeComponent(); vm = new BookViewModel(); this.DataContext = vm; } private void Button_Click(object sender, RoutedEventArgs e) { vm.MakeChange(); } } 

XAML

                       

Как указано выше, когда я нажимаю кнопку и изменяю значение в первой книге, пользовательский интерфейс не изменяется.

Тем не менее, когда я перемещаю INotifyPropertyChanged в Model, он отлично работает (обновления пользовательского интерфейса), потому что изменение находится в настройке свойств модели не в книгах в VM:

 public class Book : INotifyPropertyChanged { private string title; public string Title { get { return title; } set { if (value != title) { title = value; NotifyPropertyChanged("Title"); } } } public List Authors { get; set; } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } } 

Итак, вернемся к моему первоначальному вопросу, как мне это сделать без внедрения INotifyPropertyChanged в модели?

Благодарю.

Дело в том, что если вы следовали за MVVM, у вас был бы BookViewModel для вашего classа модели Book . Таким образом, у вас будет реализация INotifyPropertyChanged в этой модели представления. Именно для этого MVVM существует (но не только).

При этом INotifyPropertyChanged должен быть реализован на classах classов представлений, а не на моделях.

ОБНОВЛЕНИЕ : В ответ на ваше обновление и нашу дискуссию в комментариях …

By BookViewModel Я имел в виду что-то еще. Вам нужно обернуть в эту модель представления не всю коллекцию объектов Book а отдельную Book :

 public class BookViewModel : INotifyPropertyChanged { private Book book; public Book Book { get { return book; } } public string Title { get { return Book.Title; } set { Book.Title = value; NotifyPropertyChanged("Title"); } } public BookViewModel(Book book) { this.book = book; } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged(String info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } } 

И ваш BookProvider вернет ObservableCollection вместо ObservableCollection :

 public class BookProvider { public ObservableCollection GetBooks() { ObservableCollection books = new ObservableCollection(); books.Add(new BookViewModel(new Book { Title = "Book1", Authors = new List { new Author { Name = "Joe" }, new Author { Name = "Phil" } } })); books.Add(new BookViewModel(new Book { Title = "Book2", Authors = new List { new Author { Name = "Jane" }, new Author { Name = "Bob" } } })); return books; } } 

Как вы можете видеть, когда вы обновляете свойство Title в Book вы будете делать это через свойство Title соответствующей модели представления, которое приведет к событию PropertyChanged , которое приведет к обновлению пользовательского интерфейса.

Пожалуйста, прочитайте эту статью . В нем объясняется, как можно уменьшить дублирование кода, внедряя INotifyPropertyChanged в модели.

Не путайте INotifyPropertyChanged с MVVM.

Подумайте, что такое INotifyPropertyChanged на самом деле -> Это событие, которое позволяет сказать «Эй, посмотри, я изменился». Если кто-то заботится, то они могут что-то сделать, будь то View, ViewModel или что-то еще.

Давайте начнем с вашей книги (модели). Свойство Title может запускать измененное событие, почему бы и нет? Это имеет смысл, Книга имеет дело со своими собственными свойствами.

Теперь для BookViewModel – отлично, нам не нужно дублировать заголовок и заполнять наш код! Ого!

Рассмотрим вид, где мы хотим увидеть список книг или книгу со списком авторов. Ваша ViewModel может обрабатывать дополнительные свойства, специфичные для представления, такие как IsSelected. Это отличный пример: почему книга была бы осторожна, если бы она была выбрана или нет? Это ответственность за ViewModel.


Очевидно, что это зависит от вашей архитектуры, но лично, если я создаю библиотеку объектов, я реализую базовый class с INotifyPropertyChanged и сделаю свойства объекта ответственными за запуск события.

  • Похоже, что привязки данных не обновляются
  • Как правильно привязать xml к WPF DataGrid?
  • Управление несколькими выборами с помощью MVVM
  • Нажатие свойств GUI только для чтения обратно в ViewModel
  • Привязка данных Android с использованием тега include
  • WPF привязка данных к интерфейсу, а не к фактическому объекту - возможность литья?
  • Image UriSource и привязка данных
  • Как обнаружить сломанные привязки данных WPF?
  • Связывание WPF ComboBox с пользовательским списком
  • Связывающие свойства в коде
  • Привязка OneWayToSource от свойства readonly в XAML
  • Давайте будем гением компьютера.