In MVVM should the ViewModel or Model implement INotifyPropertyChanged?
I'd say quite the opposite, I always put my INotifyPropertyChanged
on my ViewModel - you really don't want to be polluting your model with a fairly WPF specific feature like INotifyPropertyChanged
, that stuff should sit in the ViewModel.
I'm sure others would disagree, but that's the way I work.
Should I have one ViewModel class implementing INotifyPropertyChanged for each Model class?
You don't need a ViewModel-Class for each Model-Class you have. Your Model-Classes should implement the INotifyPropertyChanged
-Interface.
You need ViewModels to interact with your Views. In the ViewModels you can have instances of your Model-Classes.
Btw.: To avoid writing the code for INotifyPropertyChanged
every time in each ViewModel and Model i've created an abstract base class where everything is derived from. This class looks like:
public abstract class NotifyBase : INotifyPropertyChanged
{
private readonly Dictionary<string, object> mapping;
protected NotifyBase()
{
mapping = new Dictionary<string, object>();
}
protected void Set<T>(T value, [CallerMemberName] string propertyName = "")
{
mapping[propertyName] = value;
OnPropertyChanged(propertyName);
}
protected T Get<T>([CallerMemberName] string propertyName = "")
{
if(mapping.ContainsKey(propertyName))
return (T)mapping[propertyName];
return default(T);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemeberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MVVM - PropertyChanged in Model or ViewModel?
The INotifyPropertyChanged
(INPC) interface is used for Binding
.
So, in the average case, you want to implement it in your ViewModel
.
The ViewModel
is used to decouple the Model
from your View
, so there is no need to have INPC in your Model
, as you do not want Bindings
to your Model
.
In most cases, even for smaller properties, you still have a very small ViewModel
.
If you want a solid base for MVVM
, you are probably going to use some kind of MVVM Framework like caliburn.micro. Using it will give you a ViewModelBase
(or here NotifyPropertyChangedBase
) so that you do not have to implement those interface members yourself and can just use NotifyOfPropertyChange(() => MyProperty)
, which is way easier and less error prone.
UPDATE
As there seem to be many Windows Forms developers out there, here is an excellent
article that will give deeper understanding of what MVVM is about:
MSDN Magazine on MVVM
I have linked especially the part about the datamodel, that the question is about.
Should ViewModel class implement INotifyPropertyChanged or can I use Object composition?
Well, ... ViewModels are best to be viewed as Composition, but the notification part should be an implementation of the Interface (or in your case inheritance). You have your DTOs and your ViewModels would be a composition of the DTOs, depending on the scenario.
This implementation of the same stuff can be tedious, but for WPF is still necessary. What you can do to simplify the process is to use Veawrs like Fody. It changes your observation of the ViewModel. All of the properties of the VM are by default observable properties, but you exclude the ones you do not want to, or you can define for one property to let the UI know that it should also update others.
It keeps the code very clean and simple. You will not need to implement the Interface, but it will be inherited in build time if you give the class the needed attribute.
Adding INotifyPropertyChanged to Model?
Option1.
Separate entities, which being transferred between client and server (DTO), from entities, which are models on the client side. Implement INPC
in models. Use mapping between these entities.
Option2.
Bind view to view model properties only. Make view model properties, which wrap corresponding model properties.
Option 3.
Is a mix of first two options. Do not aggregate model in view model. Use mapping between model and view model. Make view model properties, which correspond to model properties.
WPF MVVM INotifyPropertyChanged Implementation - Model or ViewModel
The thing is that if you were following MVVM, you would have a BookViewModel
for your Book
model class. So you would have a INotifyPropertyChanged
implementation on that view model. Exactly for that purpose MVVM exists (but not only).
That being said, the INotifyPropertyChanged
has to be implemented on view model classes, not models.
UPDATE: In response to your update and our discussion in comments...
By BookViewModel
I meant something else. You need to wrap in this view model not the whole collection of Book
objects but an individual 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));
}
}
}
And your BookProvider
will return ObservableCollection<BookViewModel>
instead of ObservableCollection<Book>
:
public class BookProvider
{
public ObservableCollection<BookViewModel> GetBooks() {
ObservableCollection<BookViewModel> books = new ObservableCollection<BookViewModel>();
books.Add(new BookViewModel(new Book {
Title = "Book1",
Authors = new List<Author> { new Author { Name = "Joe" }, new Author { Name = "Phil" } }
}));
books.Add(new BookViewModel(new Book {
Title = "Book2",
Authors = new List<Author> { new Author { Name = "Jane" }, new Author { Name = "Bob" } }
}));
return books;
}
}
As you can see, when you are updating the Title
property of the Book
you will be doing it through the Title
property of the corresponding view model that will raise the PropertyChanged
event, which will trigger the UI update.
Related Topics
Is There a Generic Constructor with Parameter Constraint in C#
C# Regex Split - Commas Outside Quotes
How to Use Webrequest to Access an Ssl Encrypted Site Using Https
Why Does Casting Int to Invalid Enum Value Not Throw Exception
Do You Have to Put Task.Run in a Method to Make It Async
Add Data Annotations to a Class Generated by Entity Framework
Round a Double to X Significant Figures
Implementing a Log Viewer with Wpf
Reading File Input from a Multipart/Form-Data Post
Testing If Object Is of Generic Type in C#
How to Seed a Random Class to Avoid Getting Duplicate Random Values
What Is the Purpose of Self Tracking Entities
Interprocess Communication for Windows in C# (.Net 2.0)
Optimal Linq Query to Get a Random Sub Collection - Shuffle
Get Mime Type from Filename Extension