Introduction
Remember last time, when we figured out how to bind data with different modes
here.
We used Prism's SetProperty method to update UI.
What exactly do I mean by updating UI?
We can bind properties of ViewModel with View, but is there any way to tell UI that bound properties have been modified so that the UI must update itself?
In simple words, we want to trigger UI when any bound value is modified.
To achieve this, WPF has introduced the INotifyPropertyChanged interface. It is a contract between view & viewmodel.
Let's see this in action.
Say we want to register a user & we want to calculate the user's age based on the date of birth entered by the user.
The screen will have 4 fields: User Name (TextBox), DOB (DateTimePicker), Age (TextBlock), EmailId (TextBox), Register plus Reset (Button) & response (TextBlock).
So the final window would look like this:
Now the ViewModel: MainWindowViewModel will consist of the following:
- string UserName: User Name (TextBox)
- DateTime DOB DOB (DateTimePicker)
- string Age: Age (TextBlock)
- string EmailId: EmailId (TextBox)
- ICommand RegisterButtonClicked: Register (Button)
- ICommand ResetButtonClicked: Reset (Button)
- bool IsButtonClicked: What response to display in TextBlockMessage (TextBlock)
- ViewModel will inherit INotifyPropertyChanged interface & we will override PropertyChangedEventHandler event
- Function for calculating an age based on DOB:
Let's encapsulate all of the above:
Now it's time for some action. Run this project and check out the behaviour:
There you go. As soon as DOB is modified, we call CalulateAge() method which sets the value of Age property thus Age property has been modified with new value in the background (in the C# class) now our PropertyChange event has been raised, which triggered UI and updated the value of Age)
Here is the syntax for calling a RaisePropertyChange:
- RaisePropertyChange("UserName");
You may have wonder why we have to pass the Property name as a parameter. What if someone makes a mistake while typing a name? Then it will lead to a problem.
Let's add a new method to take care of this.
- protected bool SetProperty<T>(ref T prop, T value, [CallerMemberName] string propertyName = null)
- {
- if (object.Equals(prop, value)) return false;
- prop = value;
- this.RaisePropertyChange(propertyName);
- return true;
- }
And how do we call this method?
- private string _userName;
- public string UserName
- {
- get { return _userName; }
- set {
- SetProperty(ref _userName, value);
- }
- }
See, whenever we bind the property in XAML, the value of the property gets assigned to UserName (the public property).
For example, when I enter "Rikam" in UserNameTextBox, the ViewModel's property UserName is updated with "Rikam" & _userName and the private variable will be null as per the above code.
Then SetProperty method will update _userName with "Rikam" and will raise the event with "UserName" property.
Now suppose I am entering "Rikam" in UI, but on the click of the Register button, it will change the property to "Alex".
- private void RegisterUser(object value)
- {
- UserName = "Alex";
- IsButtonClicked = true;
- }
Then SetProperty will get these parameters:
- ref T prop = "Rikam", T value = "Alex"
With respect to _userName = "Rikam" & Value(UserName) = "Alex".
Now let's see the final updated ViewModel:
- using System;
- using System.ComponentModel;
- using System.Runtime.CompilerServices;
- using System.Windows.Input;
-
- namespace A
- {
- class MainWindowViewModel : INotifyPropertyChanged
- {
- #region Properties
- private string _userName;
- public string UserName
- {
- get { return _userName; }
- set {
- SetProperty(ref _userName, value);
- }
- }
-
- private string _age;
- public string Age
- {
- get { return _age; }
- set {
- SetProperty(ref _age, value);
- }
- }
-
- private string _emailId;
- public string EmailId
- {
- get { return _emailId; }
- set {
- SetProperty(ref _emailId, value);
- }
- }
-
- private bool _isButtonClicked;
-
- public bool IsButtonClicked
- {
- get { return _isButtonClicked; }
- set {
- SetProperty(ref _isButtonClicked, value);
- }
- }
-
- private DateTime _dob;
-
- public DateTime DOB
- {
- get { return _dob; }
- set {
- SetProperty(ref _dob, value);
- CalculateAge();
- }
- }
-
- #endregion
-
- #region ICommands
- public ICommand RegisterButtonClicked { get; set; }
- public ICommand ResetButtonClicked { get; set; }
- #endregion
-
- #region INotifyChangeProperty
-
- public event PropertyChangedEventHandler PropertyChanged;
- public void RaisePropertyChange(string propertyname)
- {
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
- }
- }
-
- protected bool SetProperty<T>(ref T prop, T value, [CallerMemberName] string propertyName = null)
- {
- if (object.Equals(prop, value)) return false;
- prop = value;
- this.RaisePropertyChange(propertyName);
- return true;
- }
- #endregion
-
- #region Constructor
- public MainWindowViewModel()
- {
- RegisterButtonClicked = new RelayCommand(RegisterUser, CanUserRegister);
- ResetButtonClicked = new RelayCommand(ResetPage, CanResetPage);
- }
-
- #endregion
-
- #region Event Methods
- private void RegisterUser(object value)
- {
- _userName = "Alex";
- IsButtonClicked = true;
- }
-
- private bool CanUserRegister(object value)
- {
-
- if (string.IsNullOrEmpty(UserName))
- {
- return false;
- }
- else
- {
- return true;
- }
- }
-
- private void ResetPage(object value)
- {
- IsButtonClicked = false;
- UserName = Age = EmailId = "";
- }
-
- private bool CanResetPage(object value)
- {
- if (string.IsNullOrEmpty(UserName)
- || string.IsNullOrEmpty(EmailId))
- {
- return false;
- }
- else
- {
- return true;
- }
- }
-
- private void CalculateAge()
- {
- int Years = new DateTime(DateTime.Now.Subtract(DOB).Ticks).Year - 1;
- DateTime PastYearDate = DOB.AddYears(Years);
- Age = String.Format("{0}Years",Years);
- }
- #endregion
-
- }
- }
Classic!
There will be no change in the output.
Conclusion
In this article, we grasp knowledge on following things:
-
How to use the INotifyPropertyChanged interface with MVVM.
- How to trigger UI with modified properties.
- How to rectify error-prone code.
Thank you so much for being here, I wish you all the very best.
Keep coding.