My Blog List

Friday, April 10, 2015

MVVM

How the MVVM pattern became convenient:

WPF has a very powerful databinding feature that can directly bind two WPF elements together, but the common use of databinding is to bind some kind of data to the view. This is done by using the DataContext property.

One big limitation of using the DataContext property as data source is, that we can use only one data object. But in a real life project you usually have more than one data object per view. So the most obvious approach is to aggregate all data objects into one single object that exposes the aggregated data as properties and that can be bound to the DataContext. This object is called the view model in MVVM.

Separation of logic and presentation:

The MVVM pattern is so far only a convenient way to bind data to the view. But what about user actions, how are they handled? The classic approach, known from Win Forms is to register an event handler that is implemented in the code-behind file of the view. Doing this has some disadvantages:

  • Having event handlers in the code-behind is bad for testing, since you cannot mock away the view.
  • Changing the design of the view often also requires changes in the code, since every element has its different event handlers.
  • The logic is tightly bound to the view. It's not possible to reuse the logic in another view.

So the idea is to move the whole presentation logic to the view model by using another feature of WPF, namely Commands. Commands can be bound like data and are supported by many elements as buttons, toggle buttons, menu items, checkboxes and input bindings. The goal here is not to have any line of logic in the code-behind of a view. This brings you the following advantages;

  • The view-model can easily be tested by using standard unit-tests (instead of UI-testing).
  • The view can be redesigned without changing the view model.
  • The view-model can even be reused; in some special cases (this is usually not recommended).
What is MVVM?

The Model-View-ViewModel (MVVM) pattern helps you to cleanly separate the business and presentation logic of your application from its user interface (UI). It can make your application much easier to test, maintain, and evolve. It can also greatly improve code re-use opportunities and allows developers and UI designers to more easily collaborate when developing their respective parts of the application. 

Using the MVVM pattern, the UI of the application and the underlying presentation and business logic is separated into three separate parts:

·         Model: It encapsulates the business logic and data.

·         View: It encapsulates the UI and UI logic.

·         View Model: It encapsulates presentation logic and state.

Prism includes samples and reference implementations that show how to implement the MVVM pattern in a Silverlight or Windows Presentation Foundation (WPF) application.
 
How MVVM Works?

In MVVM, the View Model knows nothing about the view. The view interacts with the view model through data binding, commands, and change notification events. The view model queries, observes, and coordinates updates to the model, converting, validating, and aggregating data as necessary for display in the view.
The View Class:

The view's responsibility is to define the structure and appearance of what the user sees on the screen. Ideally, the code-behind of a view contains only a constructor that calls the InitializeComponent method.
 
In Silverlight and WPF, data binding expressions in the view are evaluated against its data context. In MVVM, the view's data context is set to the view model.
 
The View Model Class:

The view model in the MVVM pattern encapsulates the presentation logic and data for the view. The view model implements properties and commands to which the view can data bind and notifies the view of any state changes through change notification events via the INotifyPropertyChanged and INotifyCollectionChanged interfaces. The view model is responsible for coordinating the view's interaction with any model classes.
 
The view model exposes the model classes directly to the view so that controls in the view can bind directly to them. The view model may also implement data validation via the IDataErrorInfo or INotifyDataErrorInfo interfaces.
 
The Model Class:

The model (Entity) represents the actual data and/or information we are dealing with.The model in the MVVM pattern encapsulates business logic and data.
Note :
The view and view model are loosely coupled via the view's data context property; this allows visual elements and behaviors in the view to be data bound to properties, commands, and methods on the view model.
Creating the View Model Using XAML:

<UserControl.DataContext>

    <my:QuestionnaireViewModel/>

</UserControl.DataContext>

Creating the View Model Programmatically:

public QuestionnaireView()

{

    InitializeComponent();

    this.DataContext = new QuestionnaireViewModel();

}

Data Binding :

Data binding plays a very important role in the MVVM pattern. To ensure that the UI is kept up to date when the data changes in the view model, it should implement the appropriate change notification interface. If it defines properties that can be data bound with view, it should implement the INotifyPropertyChanged interface. If the view model represents a collection, it should implement the INotifyCollectionChanged interface or derive from the ObservableCollection<T> class that provides an implementation of this interface. Both of these interfaces define an event that is raised whenever the underlying data is changed.

In Prism we can use NotificationObject class which implements INotifyPropertyChanged interface.
 
INotifyPropertyChanged Interface:

The INotifyPropertyChanged interface is used to notify UI, typically binding UI that a property value has changed.
For example, consider a Person object with a property called FirstName. To provide generic property-change notification, the Person type implements the INotifyPropertyChanged interface and raises a PropertyChanged event when FirstName is changed.
While implementing INotifyPropertyChanged interface, it define property changed event and the event is raised when the property value got changed.

Example:

using System.ComponentModel;

public class BaseModel : INotifyPropertyChanged

    {

        private string _Name;

        public string Name

        {

            get{return _Name; }

            set{_Name = value;

                OnPropertyChanged("Name");

            }

        }

 

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string Name)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(Name));

            }

        }}

 
View:-

<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>

 INotifyCollectionChanged Interface:

To set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event that must be raised whenever the underlying collection changes.

Example:

using System.Collections.Specialized;

public class BaseCollectionModel : INotifyCollectionChanged

    {

        public event NotifyCollectionChangedEventHandler CollectionChanged;

        public void OnCollectionChanged(NotifyCollectionChangedAction Action)

        {

            if (CollectionChanged != null)

            {

                CollectionChanged(this, new NotifyCollectionChangedEventArgs(Action));

            }

        }

 

        private List<Employe> emp;

        public List<Employe> Emp

        {

            get{return  emp; }

            set{emp = value;

                OnCollectionChanged(NotifyCollectionChangedAction.Add);

            }}

    }}

WPF provides the ObservableCollection<T> class, which is a built-in implementation INotifyCollectionChanged interface.


Represents a dynamic data collection that provides notification when the item gets added, removed and whole list get refreshed. ObservableCollection<T> implements INotifyCollectionChanged which provides notification when the collection is changed.

Example:

When you click on add button, a new record has been inserted into the data context. No matter StudentInformationCollection is derived from List or ObservableCollection. But it would be updated in the ListBox UI only if you derive it from ObservableCollection. If you use List, you have reset the datacontext of WPF ListBox each and every time you make changes to the collection.

using System.Collections.ObjectModel;

private ObservableCollection<Employe> emp1;

        public ObservableCollection<Employe> Emp1

        {

            get{return emp1;}

            set{emp1 = value;}

        }

Commands:

In WPF and Silverlight, actions or operations that the user can perform through the UI are typically defined as commands. Commands provide a convenient way to represent actions or operations that can be easily bound to controls in the UI.

The view model can implement commands as either a Command Method or as a Command Object .A command object is an object that implements the ICommand interface. This interface defines an Execute method, which encapsulates the operation itself, and a CanExecute method, which indicates whether the command can be invoked at a particular time.

The Prism DelegateCommand class encapsulates two delegates that each reference a method implemented within your view model class. It inherits from the DelegateCommandBase class, which implements the ICommand interface's Execute and CanExecute methods by invoking these delegates. You specify the delegates to your view model methods in the DelegateCommand class constructor.

Example :

using System.Windows.Input;

public class DelegateCommand:ICommand

    {

       readonly Action<object> _execute;

       readonly Predicate<object> _canExecute;

       public DelegateCommand(Action<object> execute)  : this(execute, null)

        {

       }

       public DelegateCommand(Action<object> execute, Predicate<object> canExecute)

       {

           _execute = execute;

           _canExecute = canExecute;

       }

       public event EventHandler CanExecuteChanged

       {

           add { CommandManager.RequerySuggested += value; }

            remove { CommandManager.RequerySuggested -= value; }

       }

         public bool CanExecute(object parameter)

        {

            return _canExecute == null ? true : _canExecute(parameter);

        }

         public void Execute(object parameter)

        {

            _execute(parameter);

        }

    }

No comments:

Post a Comment