using of INotifyPropertyChanged - c#

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.

Related

Implement INotifyPropertyChanged on ICommand

Background
In order to implement async commands in an MVVM app I went through the following tutorials by Stephen Cleary.
https://msdn.microsoft.com/magazine/dn605875 Async Programming : Patterns for Asynchronous MVVM Applications: Data Binding
https://msdn.microsoft.com/en-us/magazine/dn630647.aspx Async Programming : Patterns for Asynchronous MVVM Applications: Commands
Problem
When reimplementing what he proposed step by step I stumbled upon the problem that the PropertyChanged event handler in the command is always null. When running Steves sample code it is not null.
In order to understand this better I started from scratch with implementing the most basic command that one could think of:
public class SimpleCommand : ICommand, INotifyPropertyChanged
{
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
// having a break point on the following line
throw new NotImplementedException();
}
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note that I have a break point set on the line that throws the NotImplementedException because I just want to see whether PropertyChanged is null or not.
The viewmodel basically just creates this command and the view binds to it via a button.
public class MainViewModel : INotifyPropertyChanged
{
public ICommand SimpleAction { get; set; }
public MainViewModel()
{
SimpleAction = new SimpleCommand();
}
...
}
The window just contains one button to call that command
<Window ...>
<Window.DataContext>
<viewModels:MainViewModel></viewModels:MainViewModel>
</Window.DataContext>
<Grid>
<Button
Command="{Binding SimpleAction}"
Content="Click Me!"></Button>
</Grid>
</Window>
My assumption is that when a command implements INotifyPropertyChanged then the framework listens onto the PropertyChanged event which is obviously wrong.
So how does it work in Steves examples then? There he just implements INotifyPropertyChanged on NotifyTaskCompletion or AsyncCommand and PropertyChanged is not null.
Looking at other SO posts the usual answer in general is that DataContext is not set. Still I don't see how to set this for a command.
Actual Question
How to implement INotifyPropertyChanged properly on a command (based on ICommand) in MVVM (C#)?
The command itself has no subscribers unless you bind to a property of the command itself.
That's what #Stephen Cleary does in his article. He binds to the Execution property of the AsyncCommand<TResult> class. You bind to the SimpleAction property of the MainViewModel class.
So in your sample code, the SimpleCommand object has no subscribers and that's why the event handler returns a null reference.

Events, methods using these events and inheritance

I am creating the program-side architecture of a software developped in WPF, I designed the architecture as being compliant with the MVVM pattern.
For many sakes (design, coherence, reusability, maintainability, scalability, etc) I created the class BaseViewModel implementing the interface INotifyPropertyChanged and some other methods:
public class BaseViewModel: INotifyPropertyChanged
{
private PropertyChangedEventHandler property_changed;
public event PropertyChangedEventHandler PropertyChanged
{
add { property_changed += value; }
remove { property_changed -= value; }
}
//Here several methods using PropertyChanged and easing the usage of ViewModels
public BaseViewModel() { }
}
The above-defined class BaseViewModel is used as a base class for all the other ViewModels of the application (or, at least, is meant to be so), for example:
public class SampleViewModel : BaseViewModel
{
//private PropertyChangedEventHandler property_changed;
//public event PropertyChangedEventHandler PropertyChanged
//{
// add { property_changed += value; }
// remove { property_changed -= value; }
//}
public String Name
{
get { return name; }
set
{
if(value != name)
{
name = value;
var handler = PropertyChanged;
if(handler != null)
{
handler(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
private String name = "";
public SampleViewModel ()
: base() { }
}
I use the class SampleViewModel as the DataContext of SampleUserControl which bares a DependencyProperty:
public partial class SampleUserControl : UserControl
{
#region ViewModel
public SampleViewModel ViewModel
{
get { return view_model; }
}
private SampleViewModel view_model = new SampleViewModel();
#endregion
#region DependencyProperty
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(SampleUserControl),
new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(TextPropertyChangedCallback)));
private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SampleUserControl sender = d as SampleUserControl;
if (sender != null)
{
sender.ViewModel.Name = (String)e.NewValue;
}
}
#endregion
public SampleUserControl()
{
InitializeComponent();
LayoutRoot.DataContext = ViewModel;
ViewModel.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
SampleViewModel viewmodel = sender as SampleViewModel;
if (viewmodel != null)
{
switch (e.PropertyName)
{
case "Name":
SetValue(TextProperty, viewmodel.Name);
break;
default:
break;
}
}
}
}
To sum up, the data relative to SampleUserControl are contained at three locations : the instance of SampleViewModel, within TextProperty and within the property Text of a TextBox in the xaml part of SampleUserControl(this property Text is twoway-bound through Binding with the field Name of ViewModel).
To synchronize the three values, I added the methods TextPropertyChangedCallback and ViewModel_PropertyChanged which update the fields which need to be updated.
The above code works and the three above-mentionned locations are kept up-to-date, events fire and so on, things are fine when SampleUsercontrol is consumed with data-binding.
But SampleViewModel fires the event BaseViewModel.PropertyChanged, and since BaseViewModel is meant to be extensively used, I would like each ViewModel to have its own event PropertyChanged, at least in order to avoid overlapping events.
So I uncomment the code of SampleViewModel thus redefining the event PropertyChanged but it breaks down the synchronization between the field Name of the instance of SampleViewModel and the property TextProperty of SampleUserControl.
Am I making some mistakes on the conception side?
Do you have any guidance for me?
What is the best economic way of defining a different event PropertyChanged for each ViewModel inheriting from BaseViewModel while still using the general-purpose methods defined within that base class (such methods use PropertyChanged)?
(I would like to avoid having heavy pieces of code to copy-paste.)
I know that it is more about optimization, but such optimizations can make a difference between a slow software and a fast one. I am at the stage of code-factoring, so I fancy nicely-shaped, elegant and factorized code.
End of the day happening, I may miss some obvious solutions.
Thanks in advance for any clue,
Julien
TL;DR: Basically, I would double-check that you are doing your DC/DP on that user control correctly, and toss out any concept of multiple definitions of PropertyChanged
In detail:
You defined PropertyChanged in the base class, which is great. There is no reason to ever redefine it anywhere else. Really, you are just asking for trouble by doing this.
Related to that, you should really just make a method to do the event invocation rather than doing the whole handler bit in the settter. Insta-reduction of copy paste.
The fact that you are having to use TextPropertyChanged is a huge red flag here. Which relates to the real problem, that you are probably abusing your dependency property. DPs are used to allow parent controls to bind to a property of your user control. You typically won't use them in conjunction with a data context internal to the control because, as you have seen, keeping them in sync is a nightmare.
In general, user controls should only have their own data context if they are set up to stand apart from any other control (ie, a sub-view). If they are just a fancy control, then giving them a view model rarely gets you anything.

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

MVVM INotifyPropertyChanged conflict with base class PropertyChange

I'm relatively new to MVVM and I'm trying to understand how INotifyPropertyChanged interface works and how to implement it in my models. The approach that I decided to take was to implement it in each of my Business Object classes. The problem with that approach is that when I bind my View to a property in a Base class the PropertyChanged event in that base class never gets initialized (is null) and therefore the View does not refresh the data for that element when my Model changes. I was able to reproduce the problem with the example below.
I have a Person Base class:
public class Person : INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
private String _name;
}
And I have an Employee class inheriting from my Person Base class:
public class Employee : Person,INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String EmployeeID
{
get
{
return _employeeId;
}
set
{
_employeeId = value;
RaisePropertyChanged("EmployeeID");
}
}
private String _employeeId;
}
Here my View Model:
public class ViewModel : ViewModelBase<ViewModel>
{
private Employee _employee;
public ViewModel()
{
ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel);
Employee = new Employee()
{
Name = "BOB",EmployeeID = "1234"
};
}
public ICommand ChangeModelCommand { get; set; }
public Employee Employee
{
get
{
return _employee;
}
set
{
this._employee = value;
NotifyPropertyChanged(m=>m.Employee);
}
}
public void ChangeModel()
{
MessageBox.Show("CHANGING MODEL");
this.Employee.Name = "MIKE";
this.Employee.EmployeeID = "5678";
}
public bool CanChangeModel
{
get{ return true;}
}
}
And finally my View:
<Window.Resources>
<MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource Model}">
<StackPanel>
<Label Content="Employee Name"/>
<TextBox Text="{Binding Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Label Content="Employee ID"/>
<TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/>
</StackPanel>
</Grid>
In this example I initialize my Employee VM Property in the VM constructor and then I have a command to modify the EmployeeID (from Employee class) and Name (from Person Class). However, the only UI element in the View that gets updated is the EmployeeID and not the Name (I expected Bob to update to Mike). While debugging I found that PropertyChanged event was always null in my base class (Person). I also noticed that when I remove the whole #INotifyProperty region from my Employee class everything works fine since it is using the Base Type event and methods.The problem I have with that is that all my current model classes implement INotifyPropertyChanged explicitly. They all define a PropertyChanged event and implement the RaisePropertyChanged method, which obviously will impact my bindings in my MVVM application. Lastly, I want to clarify that I do not want wrap my Model properties in my ViewModel and rely on the VM INPC mechanism. I would like to use my Model INPC implementation already in place whithout having to conditionally remove the INPC implementations depending on whether I am inheriting or not from a base type.
In summary, I would like to know what's the best way to implement the INPC in my deeply hierarchical model so that inheritance doesn't break the PropertyEvent propagation as we saw in this example and so my independent classes can be self sufficient as well. Any ideas or suggestions will be greatly appreciated :)
Simply make RaisePropertyChanged protected and move it into the base class. Currently you will have a lot of duplication that is not necessary.
Something like this:
protected virtual void RaisePropertyChanged(string propertyName);
Many MVVM frameworks provide this for you. For example PRISM has a NotificationObject ViewModel base class.
You should only implement INPC once, you can use the same raising method in the subclasses.
I would also change the raise property changed method to use reflection instead of passing in hard coded strings. I see you did it in your view model but not in your models (where most of the errors tend to occur).

Categories

Resources