How to implement Property Change Notification - c#

In MVVM how should I implement INotifyPropertyChanged interface: in a ViewModel class or in a Model class? How to handle model's property changed event if INotifyPropertyChanged interface has been implemented in a ViewModel?

First, you always implement it in your View Model, because that interface is used by the framework to update the UI when you updated data in the view model.
You can implement it in the Model, but it is by no means required. If the Model is changing out from under you, you could, and likely should, easily raise your own (semantically clearer) events that the View Model listens to in order to update its data.
The actual implementation should look like this (MSDN):
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

Related

Should I have one ViewModel class implementing INotifyPropertyChanged for each Model class?

Basically, I have a model with various classes that load my data in different collections, including collections of collections (e.g. Cart has a collection of Bundle, which has collections of Product) . If my understanding of MVVM is correct, I would need to make one ViewModel class that implements INotifyPropertyChanged (directly or through inheritance from a base class) for each of my model classes. Though I must admit it seems to me that it implies a lot of duplicated code, just, having the ViewModel associate each property of the model class with a OnPropertyChanged call.
Just like is shown in this article for instance.
Am I getting this right ?
I'm currently trying to understand the basics of MVVM, so I try to fully implement it in my programs without any additional framework (MVVM Light and others).
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));
}
}
}

using of INotifyPropertyChanged

Can someone explain me why need to use implementation of INotifyPropertyChanged when using binding in wpf?
I can bind properties without implementation of this interface?
For example i have code
public class StudentData : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _firstName = null;
public string StudentFirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
And binding in .xaml
<TextBox Text="{Binding Path=StudentFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center" />
this code from .xaml.cs
StudentData _studentData = new StudentData { StudentFirstName = "John", StudentGradePointAverage = 3.5};
public MainWindow()
{
InitializeComponent();
this.DataContext = _studentData;
}
why we need to use INotifyPropertyChanged in this case?
It is not my code.
You need INotifyPropertyChanged if you want a wpf form to be automatically updated when a property changes through code. Also some controllers might want to know if edits have been made in order to enable/disable a save-button, for instance. You also might be displaying the same property on different views; in this case INotifyPropertyChanged helps to immediately update the other view when you edit a property.
If you think that your form behaves well without INotifyPropertyChanged, then you can drop it.
Note that binding works even without INotifyPropertyChanged. See: Why does the binding update without implementing INotifyPropertyChanged?
I would implement the properties like this. In some rare cases it can help to avoid endless circular updates. And it is more efficient by the way.
private string _firstName;
public string StudentFirstName
{
get { return _firstName; }
set
{
if (value != _firstName) {
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
Starting with C#6.0 (VS 2015), you can implement OnPropertyChanged like this:
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When you bind to a property of StudentData such as the StudentFirstName then the binding class tests to see if the StudentData instance provides the INotifyPropertyChanged interface. If so then it will hook into the PropertyChanged event. When the event fires and it fires because of the StudentFirstName property then it knows it needs to recover the source value again because it has changed. This is how the binding is able to monitor changes in the source and reflect them in the user interface.
If you do not provide the INotifyPropertyChanged interface then the binding has no idea when the source value changes. In which case the user interface will not update when the property is changed. You will only see the initial value that was defined when the binding was first used.
It does need to be implemented in order for binding to work but that doesn't mean you always have to do it yourself. There are other options like Castle Dynamic Proxy (which wraps your classes in a proxy and injects INPC into all virtual properties) and Fody (which adds it to the IL in a post-processing step). It's also possible to implement yourself while at the same time reducing code bloat, as demonstrated in my answer to this question.

ObservableCollection along with a repository

I am having trouble with grasping the concept of a ObservableCollection inside MVVM. For start I would like to point out that I am doing this in a Windows 8/Metro App, not WPF or Silverlight.
According to microsoft documentation, this collection has the following usefulness:
"Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed." From what I understand this helps you a lot when binding is involved. On the net I found a lot of simple examples, by creating a ObservableCollection on runtime and then working on it, but I didn't find out what is the proper way of using this collection with a repository.
Let' say I have the following repository interface that is an implementation for a ORM database backend, or a raw ADO.NET implementation
public interface IRepository<T>
{
ObservableCollection<T> GetAll();
void Create();
void Update();
void Delete();
T GetByKey(object key);
}
and a simple ViewModel that use the repository as a model
public class ViewModel
{
private ObservableCollection<Dummy> _obsListDummy;
private RelayCommand _addCommand,_deleteCommand,_updateCommand;
private IRepository<Dummy> _repositoryDummy;
public class ViewModel()
{
_repositoryDummy=Factory.GetRepository<Dummy>();
}
public ObservableCollection<Dummy> ObsListDummy
{
get
{
return _repositoryDummy.GetAll();
}
}
public RelayCommand AddCommand
{
get
{
if (_addCommand == null)
{
_addCommand = new RelayCommand(p => DoAdd();
//DoAdd method shows a popup for input dummy and then closes;
);
}
return _myCommand;
}
}
........
}
My view would be a simple XAML with a grid, also Dummy object has INotifyPropertyChanged implemented.
Right now with this implementation after adding or updating or deleting, the ObservableCollection isn't refreshing, I know I could have put IEnumerable instead, but I dont'see an elegant solution of how would make repository to sync with the ObservableCollection that is in the model, other than subscrbing to CollectionChanged and there you treat all the states, but to it seems that I would repeat myself along with the logic that I do in the repository. And to make matters even worse, let's say I would like to get some push notification from my repository, towards the ObservableCollection.
I hope I was understand about my problem.
Thanks in advance.
You should implement INotifyPropertyChanged on your ViewModel and your ObsListDummy property should inform the ViewModel about changes applied to the collection. So it should look like this:
public class ViewModel: INotifyPropertyChanged
{
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private ObservableCollection<Dummy> _dummyCollection;
public ObservableCollection<Dummy> DummyCollection
{
get { return _dummyCollection; }
set
{
// Set the value and then inform the ViewModel about change with OnPropertyChanged
_dummyCollection = value;
OnPropertyChanged("DummyCollection");
}
}
}
This whole INotifyPropertyChanged interface and implementation includes some dirty work like declaring event and creating a helper method to raise the event so I would suggest you to use some libraries for that like MVVM Light.
You should use a member of type ObservableCollection to store your Dummy ViewModels. In your Initialize method you read the dummies from the repository, create Dummy ViewModels and put those in the ObservableCollection. Now your view will get updated, when you use Binding to ObsListDummy (and add / remove from that collection, also note that Binding only works with public properties).
Right now, you just have a new ObservableCollection on each read, no events involved, so your View will never know about a change.
Further your ViewModel shall implement INotifyPropertyChanged.

Monitoring other classes with one class

I have one class named DataClass. This Class is responsible to saving information in database, and In this class there are some methods for saving and reading from database, Except this class I have other classes called HTMLEditor, QueryBuilder , EmailSending, InforDetails.
I need to listen to other classes by my data class , any time their information are changed then my Dataclass would be notified to save these information.
I know there is one design pattern is called observer design pattern , with this design pattern, other classes(observers) are listening to one class(subject),any time the status of subject is changed then other observers are notified.
What should I do for this problem? Is there any design pattern for this situation?
I think the interface you seek if INotifyPropertyChanged.
Microsoft Documentation: INotifyPropertyChanged
The implementation is very simple.
In every property set you do:
public bool MyProperty
{
get { return myField; }
set
{
if (myField != value)
{
myField= value;
NotifyPropertyChanged();
}
}
}
And the method and events:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Every observer only need to register to that event and they get a feedback when a property changed and which one did.
As extra, some control like PropertyGrid automatically register themselves when you feed them an object that implement that interface.
The INotifyPropertyChanged interface could be what you're after:
See here: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
You basically subscribe to an event within your other classes and those classes raise the event when a property changes.
Also, this SO question has an answer that is quite cool: Automatically INotifyPropertyChanged

What's kind of event happend on target control when I use errorProvider.SetIconAlignment

Does anybody know what's kind of event happend on target control when I use errorProvider.SetIconAlignment() method?
for example:
When I call errorProvider.SetIconAlignment(mytextbox1, ErrorIconAlignment.MiddleRight);
on mytextbox1 I want to catch this event whenever SetIconAlignment was called?
I don't see an event that ErrorProvider could be using. In fact, I can't find any event at all that's related to this.
Based on what I've used from ErrorProvider, there is no other way than to extend the method, like this:
// Defines an extended version of the ErrorProvider
public class ExtendedErrorProvider : ErrorProvider, INotifyPropertyChanging, INotifyPropertyChanged
{
// That will replace the SetIconAlignment from the base class when you call it from outside the class
public void SetIconAlignment(Control control, ErrorIconAlignment value)
{
// Will raise an event just before changing the property
OnPropertyChanging("IconAlignment");
// Changed the property using the base class
base.SetIconAlignment(control, value);
// Will raise an event just after the property has changed
OnPropertyChanged("IconAlignment");
}
// This will ensure that whenever you bind methods to be called on the PropertyChanging, they will get called for the specific property...
protected void OnPropertyChanging(string property) { if (PropertyChanging != null) PropertyChanging(this, new PropertyChangingEventArgs(property)); }
public event PropertyChangingEventHandler PropertyChanging;
// This will ensure that whenever you bind methods to be called on the PropertyChanged, they will get called for the specific property...
protected void OnPropertyChanged(string property) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property)); }
public event PropertyChangedEventHandler PropertyChanged;
}
Now, outside this class, you can do something like this:
errorProvider1.PropertyChanging += WhatNeedsToBeDoneBeforeChanging(...);
errorProvider1.PropertyChanged += WhatNeedsToBeDoneAfterChanging(...);

Categories

Resources