In regular MVVM pattern, Model handles data and other database functions. But, if we do not want our application to directly communicate to the database but rather via Web Service, then all the responsibilities of Model need to be transferred to web service and we do not give the service reference directly to the main project to use the web service.
We need to create different projects for this work. Let's understand the architecture for the same.
Step 1
Let's create one WPF project, as shown in the above screenshot.
Step 2
Views (Windows and User controls) need to be added in this main project.
Step 3
Add another C# library project to the solution. I named it as WebService.
Add the reference of your service to this project (See the snapshots for better understanding).
Step 4
Add another C# library project to the Solution that will be ‘ViewModels’ and add the reference of Service project to Main project and ViewModel project.
Add the reference of ViewModel project to Main project.
So, this was all about how to manage the architecture. Now, let's see a little about how this pattern will work and follow the MVVM along with how the "PropertyChanged" nofications and event notifications will work.
- Add a window under Views folder in Main project.
Now, we have added three textboxes to fill the details for an organization - Name, Username, and Password.
- Each View must have corresponding ViewModel. So, let's add ViewModel for company details.
As we know, we need PropertyChanged notification events, InotifyPropertyChanged needs to be written for each ViewModel properties. Commands to handle click events also need to be written for each ViewModel.
So, we should create a common layer that will contain all these common things and we can directly access or reference them wherever we need. So, let's pass a CommonLayer.
Add class named as "BaseViewModel" that consists of all InotifyPropertyChanged for properties.
- namespace CommonClasses {
- public class BaseViewModel
- {
- #region INotifyPropertyChanged Members
-
-
-
-
- public virtual void RaisePropertyChanged(string propertyName) {
- OnPropertyChanged(propertyName);
- }
-
-
-
- public event PropertyChangedEventHandler PropertyChanged;
-
-
-
-
- protected virtual void OnPropertyChanged(string propertyName) {
- PropertyChangedEventHandler handler = this.PropertyChanged;
- if (handler != null) {
- var e = new PropertyChangedEventArgs(propertyName);
- handler(this, e);
- }
- }#endregion
- }
- }
The above code shows that we have created the PropertyChanged event notifications independent of any ViewModel or any property. So, we can easily differentiate between the different Views and ViewModel properties on the basis of some token GUID variable. We will be discussing that in the next article when we will create a sample application.
Let's concentrate only on the architecture for this article.
Let's see what we need to do for Click Event Commands in CommonClass.
- namespace CommonClasses {
- public class CommandClass: ICommand {
- #region Fields
- readonly Action < object > _execute;
- readonly Predicate < object > _canExecute;
- #endregion // Fields
- # region Constructors
-
-
-
-
- public CommandClass(Action < object > execute): this(execute, null) {}
-
-
-
-
-
- public CommandClass(Action < object > execute, Predicate < object > canExecute) {
- if (execute == null) throw new ArgumentNullException("execute");
- _execute = execute;
- _canExecute = canExecute;
- }
- #endregion // Constructors
- # region ICommand Members[DebuggerStepThrough]
- public bool CanExecute(object parameter) {
- return _canExecute == null ? true : _canExecute(parameter);
- }
- public event EventHandler CanExecuteChanged {
- add {
- CommandManager.RequerySuggested += value;
- }
- remove {
- CommandManager.RequerySuggested -= value;
- }
- }
- public void Execute(object parameter) {
- _execute(parameter);
- }#endregion
- }
- public class CommandClass < T > : ICommand {
- private Action < T > methodToExecute;
- private Func < T, bool > canExecuteEvaluator;
- public event EventHandler CanExecuteChanged {
- add {
- CommandManager.RequerySuggested += value;
- }
- remove {
- CommandManager.RequerySuggested -= value;
- }
- }
- public CommandClass(Action < T > methodToExecute, Func < T, bool > canExecuteEvaluator) {
- this.methodToExecute = methodToExecute;
- this.canExecuteEvaluator = canExecuteEvaluator;
- }
- public CommandClass(Action < T > methodToExecute): this(methodToExecute, null) {}
- private bool CanExecute(T parameter) {
- if (this.canExecuteEvaluator == null) return true;
- return this.canExecuteEvaluator.Invoke(parameter);
- }
- private void Execute(T parameter) {
- this.methodToExecute.Invoke(parameter);
- }
- public bool CanExecute(object parameter) {
- return this.CanExecute((T) parameter);
- }
- public void Execute(object parameter) {
- this.Execute((T) parameter);
- }
- }
- }
The above common code needs to be written in command Common Class.
Now, let's see how to use reference of the above two classes in ViewModel.
- Add reference of CommonClass project to ViewModel project.
- Inherit the common class BaseViewModel.
- namespace ViewModels
- {
- public class CompanyDetailsViewModel:BaseViewModel
- {
- }
- }
That's it.