Wednesday, December 1, 2010

MVVM - Silverlight

The Model View ViewModel (MVVM) is an architectural pattern used in software engineering that originated from Microsoft as a specialization of the Presentation Model design pattern introduced by Martin Fowler.

Why MVVM & Why not MVC or MVP:

In the MVC pattern, the Model is the data, the View is the user interface, and the Controller is the programmatic interface between the view, the model, and the user input.
This pattern, however, does not work well in declarative user interfaces like WPF or Silverlight. Reason, the XAML that these technologies uses can define some of the interface between the input and the view (Using Data Binding, Triggers, and states can be declared in XAML).

Model-View-Presenter (MVP) is another common pattern for layering applications.
In the MVP pattern, the presenter is responsible for setting and managing state for a view.
Like MVC, MVP does not quite fit the Silverlight model because the XAML might contain declarative Data Binding, Triggers, & State Management.

So where does that leave us?

Luckily for Silverlight , the WPF community has rallied behind a pattern called Model-View-ViewModel (MVVM).
This pattern is an adaptation of the MVC and MVP patterns in which:
·         The ViewModel provides a data model and behavior to the View. This allows the View to declaratively bind to the ViewModel.
·         The View becomes a mix of XAML and C#.
·         The Model represents the data available to the application, and
·         The ViewModel prepares the Model in order to bind it to the View.

Note: As the MVVM pattern is designed to support WPF and Silverlight, this pattern is only newly Available To The Public, as opposed to MVC or Model View Presenter (MVP).


MVVM:

Largely based on the MVC pattern, MVVM is targeted at modern UI development platforms (WPF & Silverlight).
MVVM pattern designed to gain two things.
·         The advantages of separation of functional development provided by MVC
·         And leveraging the advantages of XAML and the WPF, by binding data as close as possible to the Model while using the XAML. Thus minimizing the need for "code behind," especially in the View


·         MVVM was designed to make use of specific functions in WPF & Silverlight, to better facilitate the separation of View layer development from the rest of the pattern.
·         This is done by removing virtually all "code behind" from the View layer.
·         Instead of requiring designers to write View code, they can use the native WPF markup language XAML and Create Bindings To The Viewmodel, which is written and maintained by application developers.
·         This separation of roles allows designers to focus on UX needs rather than programming or business logic, allowing for the layers of an application to be developed in multiple work streams.


Elements of the MVVM pattern are described as below - Also similartiies with MVC.


Model
As in the classic MVC pattern, the model refers to either

(a)   An object model that represents the real state content (an object-oriented approach), or
(b)   The data access layer that represents that content (a data-centric approach).

View
As in the classic MVC pattern, the view refers to all elements displayed by the GUI such as buttons, windows, graphics, and other controls.

ViewModel
The ViewModel is a "Model of the View" that serves in data binding between the View and the Model.
The View-Model of MVVM is responsible for exposing the data objects from the Model, in such a way that those objects are easily consumed in XAML.

It is similar to the Controller (in the MVC pattern) that acts as a Data Binder that changes Model information into View information and passes commands from the View into the Model.

The ViewModel exposes public properties, commands, and abstractions.

Controller
some references for MVVM also include a Controller layer or illustrate that the ViewModel is a specialized functional set in parallel with a Controller, while others do not.

This difference is an ongoing area of discussion regarding the standardization of the MVVM pattern.


Criticism

 

There are currently three main areas of criticism regarding the MVVM pattern.

1.    MVVM currently lacks standardization from Microsoft both in implementation and in toolsets
2.    The overhead in implementing MVVM is "overkill" for simple UI operations. Also for larger applications, generalizing the View layer becomes more difficult.
3.    Moreover, data binding, if not managed well, can result in considerable memory consumption in an application.
4.    Exercise in creating large numbers of data bindings to the ViewModel results in duplicate code and maintenance problems.

Implementation:







Model

namespace Arun.Manglick.Silverlight.Model
{
    public class Product : INotifyPropertyChanged
    {
        #region Private Variables

        private int productId;       
        private string modelNumber;
        private string modelName;
        private double unitCost;
        private string description;

        #endregion

        #region Constructor

        public Product()
        {
        }

        public Product(string modelNumber, string modelName,double unitCost, string description)
        {
            ModelNumber = modelNumber;
            ModelName = modelName;
            UnitCost = unitCost;
            Description = description;
        }

        #endregion

        #region Properties

        public int ProductId
        {
            get { return productId; }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("Product Id - Can't be less than 0.");
                }
                else
                {
                    productId = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("ProductId"));
                }
            }
        }       
        public string ModelNumber
        {
            get { return modelNumber; }
            set {
                modelNumber = value;
                OnPropertyChanged(new PropertyChangedEventArgs("ModelNumber"));
            }
        }
        public string ModelName
        {
            get { return modelName; }
            set {
                modelName = value;
            OnPropertyChanged(new PropertyChangedEventArgs("ModelName"));
            }
        }
        public double UnitCost
        {
            get { return unitCost; }
            set
            {
                if (value < 0)
                {
                    throw new ArgumentException("Can't be less than 0.");
                }
                else
                {
                    unitCost = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("UnitCost"));
                }
            }
        }
        public string Description
        {
            get { return description; }
            set {
                description = value;
                OnPropertyChanged(new PropertyChangedEventArgs("Description"));
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        ///
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        ///
        /// </summary>
        /// <param name="e"></param>
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

        #endregion
    }
}



ViewModel

namespace Arun.Manglick.Silverlight.ViewModels
{
    public class ProductViewModel : INotifyPropertyChanged
    {
        #region Variables

        Product theProduct;
        ObservableCollection<Product> theProducts = new ObservableCollection<Product>();
        public event EventHandler LoadComplete;

        #endregion
       
        #region .ctor
        public ProductViewModel()
        {
        }
        #endregion

        #region Properties

        public ObservableCollection<Product> AllProducts
        {
            get
            {
                return theProducts;
            }
            set
            {
                theProducts = value;
                this.NotifyPropertyChanged("AllProducts");
            }
        }

        public Product SingleProduct
        {
            get
            {
                if (theProducts.Count > 0)
                    return theProducts[0] as Product;

                return null;
            }
            set
            {
                theProduct = value;
                this.NotifyPropertyChanged("SingleProduct");
            }
        }

        #endregion

        #region Methods

        public void Refresh()
        {
            ObservableCollection<Product> lst = GetData();
            AllProducts = lst;
            SingleProduct = theProducts[0] as Product;
            if (LoadComplete != null) LoadComplete(this, null);
        }

        private ObservableCollection<Product> GetData()
        {
            // This could be a Service Call.
            ObservableCollection<Product> lst = new ObservableCollection<Product> {
                new Product{ ProductId=1, ModelNumber="AA", ModelName="AAA", UnitCost=12, Description= "AA DESC"},
                new Product{ ProductId=1, ModelNumber="BB", ModelName="BBB", UnitCost=12, Description= "BB DESC"},
                new Product{ ProductId=1, ModelNumber="CC", ModelName="CCC", UnitCost=12, Description= "CC DESC"}
            };
            return lst;
        }

        #endregion

        #region Property Changed Implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion
    }
}




View

<navigation:Page x:Class="Arun.Manglick.Silverlight.Views.SimpleBindingProducts"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
                 xmlns:ViewModel="clr-namespace:Arun.Manglick.Silverlight.ViewModels"
                 xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
    <UserControl.Resources>
        <ViewModel:ProductViewModel x:Key="TheProductViewModel"
                                    LoadComplete="viewModel_LoadComplete"
                                    d:IsDataSource="True"></ViewModel:ProductViewModel>
    </UserControl.Resources>
    <StackPanel>
        <Grid Name="gridProductDetails"
              DataContext="{Binding Path=SingleProduct, Mode=TwoWay, Source={StaticResource TheProductViewModel}}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <TextBlock Margin="7">Product ID:</TextBlock>
            <TextBox Margin="5" Grid.Column="1" x:Name="txtProductId" Text="{Binding ProductId, Mode=TwoWay}"></TextBox>
            <TextBlock Margin="7" Grid.Row="1">Model Number:</TextBlock>
            <TextBox Margin="5"   Grid.Row="1" Grid.Column="1" Text="{Binding ModelNumber, Mode=OneWay}"></TextBox>
            <TextBlock Margin="7" Grid.Row="2">Model Name:</TextBlock>
            <TextBox Margin="5"   Grid.Row="2" Grid.Column="1" Text="{Binding ModelName,Mode=TwoWay}"></TextBox>
            <TextBlock Margin="7" Grid.Row="3">Unit Cost:</TextBlock>
            <TextBox Margin="5" Grid.Row="3" Grid.Column="1" Text="{Binding UnitCost, Mode=TwoWay}"></TextBox>
            <TextBlock Margin="7,7,7,0" Grid.Row="4">Description:</TextBlock>
            <TextBox Margin="7" Grid.Row="4" Grid.Column="1" Text="{Binding Description , Mode=TwoWay}"></TextBox>           
            <StackPanel Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Vertical">
                <ProgressBar Height="20" Visibility="Collapsed" IsIndeterminate="True" x:Name="loadingBar" />              
            </StackPanel>
        </Grid>
        <sdk:DataGrid AutoGenerateColumns="True" Name="dataGrid1"
                      ItemsSource="{Binding Path=AllProducts, Mode=TwoWay, Source={StaticResource TheProductViewModel}}" />
    </StackPanel>
</navigation:Page>



namespace Arun.Manglick.Silverlight.Views
{
    public partial class SimpleBindingProducts : Page
    {
        ProductViewModel viewModel = null;

        #region Constructor

        /// <summary>
        ///
        /// </summary>
        public SimpleBindingProducts()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(SimpleBindingProducts_Loaded);
        }

        #endregion

        #region Events

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SimpleBindingProducts_Loaded(object sender, RoutedEventArgs e)
        {
            loadingBar.Visibility = Visibility.Visible;
            viewModel = Resources["TheProductViewModel"] as ProductViewModel;
            viewModel.Refresh();
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void viewModel_LoadComplete(object sender, System.EventArgs e)
        {
            if (loadingBar != null) loadingBar.Visibility = Visibility.Collapsed;
        }

        #endregion
    }
}


Hope this helps.

Thanks & Regards,
Arun Manglick

Design pattern - IOC & DI

The Inversion of Control (IoC) pattern, is also known as Dependency Injection. Or In other words - IOC is implemented using DI. Or DI is the main method to implement IoC.
The target behind applying IOC and DI is to build Loosely Coupled Software Architecture.

IoC is not a new concept, however. It has been around for several years now. Using OO design principles and features such as Interface, Inheritance, and Polymorphism, the IoC pattern enables better software design that facilitates reuse, Loose Coupling, and easy testing of software components

The basic principle of IOC stands on the base of Bollywood principle – "Do not call us we will call you".
In other words it like aggregated class (here Address) saying to the container class (here Customer), do not create me I will create myself using some one else.

This article discusses IoC and demonstrates how to use this pattern in your software design with/without using any of the open source frameworks.

IoC Design Pattern

Lets understand this with an example.

Assume Class A has a relationship with Class B: it wants to use the services of Class B. The usual way to establish this relationship is to instantiate Class B inside Class A.




public class A
{
  private B b;

  public A()
  {
    b=new B();
  }
}

Listing 1 - Class A Directly Refers Class B 


public class A
{
  private B b;

  public A()
  {
    C c=new C();
    b=new B(c);
  }
}

Listing 2. Class A Directly Refers Class B and Class C

Though this approach works, it creates tight coupling between the classes. You can't easily change Class B without modifying Class A.
Here are the problems.

·         This design assumes that - Class B is a concrete class that has a default constructor. Now If Class B is changed to have a non-default constructor, then Class A would also require a change.
·         Also If Class B changed to have a non-default constructor, which takes Class C , then again the Class A would require a change.
·         Now If Object "a" owns both Object "b" and Object "c". If Class B or Class C changes at all, then Class A needs to change as well.

In essence, a simple design of a simple class with implicit design assumptions becomes a maintenance nightmare in the future. Consider how difficult making changes would be if you had this scenario in a typical application with several classes.

Here comes the usage of 'IoC pattern Framework'.

Let's re-understand the above problem with realistic objects.
In the above code, the biggest issue is the tight coupling between classes. The same is found here in real-time example also.

IOC - Problem


Here, the Customer class depends on the Address object. So for any reason Address class changes it will lead to change and compiling of 'ClsCustomer' class also. I.e. You can't easily change Address class without modifying 'ClsCustomer' Class. For e.g.

·         If Class Address is changed to have a non-default constructor, then Class Customer would also require a change.
·         Now If Object "Customer" owns two Objects "Address" and "SocietyDetail". If these two Class changes at all, then Class Customer needs to change as well.

So let's put down problems with this approach:

  • The biggest problem is that Customer class controls the creation of Address object.
  • Address class is directly referenced in the Customer class which leads to tight coupling between address and customer objects.
  • Customer class is aware of the Address class type. So if we add new Address types like home address, office address it will lead to changes in the customer class also as customer class is exposed to the actual address implementation.

In essence - If for any reason the Address object is not able to create,  the whole Customer class will fail in the constructor initialization itselfVery High/Tight Coupling.

Solution: IoC

The main problem roots from the customer class creating the address object. The solution is:

·         Shift the task/control of object creation from the customer class to some other entity – Problem Solved.
·         In other sentence if we are able to Invert this control to a third party we have found our solution. So the solution name is IOC (Inversion of control).

This is the opposite of using an API, where the developer's code makes the invocations to the API code. Hence, frameworks Invert the control: it is not the developer code that is in charge, instead the framework makes the calls based on some stimulus. I.e. Do not call us we will call you.

This solutiuon Achieves The Decoupling, and is refrerred to as - IOC (Inversion of control).

Here is the solution detail - Expose a method which allows us to set the address object. I.e. Let the address object creation be delegated to the IOC framework. IOC framework can be a class, client class or some kind of IOC container. So it will be two step procedure IOC framework creates the address object and passes this reference to the customer class.

Solution – Using DI

clsAddress objAddress = new clsAddress(..);

clsCustomer objCustomer = new clsCustomer;
objCustomr.setAddress(objAddress); // IOC Framework


The basic principle of IOC stands on the base of Hollywood principle - Do not call us we will call you (Translating for struggling actors)
In other words it like Address class saying to the Customer class, Do Not Create Me I Will Create Myself Using Some One Else.

There are two principles of IOC:

  • Main classes (Here like Customer) aggregating other classes (Here like Address) should not depend on the direct implementation of the aggregated classes (Here like Address). Both the classes should depend on abstraction. So the customer class should not depend directly on the address class. Both address and customer class should depend on an abstraction either using interface or abstract class.
  • Abstraction should not depend on details, details should depend on abstraction.


Ok, now we know the problem, let's try to understand the broader level solution. IOC is implemented using DI (Dependency injection).
We have discussed on a broader level about how to inject the dependency in the previous sections. In this section we will dive deeper in to other ways of implementing DI.

Several open source IoC frameworks like Windsor Container, Castle Windsor, Spring, PicoContainer, and HiveMind support the IoC pattern. While the general IoC principle is simple, each of these frameworks supports different implementations and offers different benefits. The IoC pattern can be implemented in four ways, as mentioned below.



The figure shows how IOC and DI are organized. So we can say IOC Is A Principle while DI Is A Way Of Implementing IOC. In DI we have four broader ways of implementing the same:

  • Constructor way
  • Exposing setter and getter (As in above examples)
  • Interface implementation
  • Service locator

Constructor Methodology

In this methodology we pass the object reference in the constructor itself. So when the client creates the object he passes the object in the constructor while the object is created.
Its main advantage is that only the creator knows about the referenced object.
This methodology is not suited for client who can only use default constructors. Then you need to go with a setter-based IoC.

IOC - Constructor Methodology


Figure: - Constructor based DI

Setter and Getter

This is the most commonly used DI methodology. The dependent objects are exposed through set/get methods of classes.
Setter-based IoC is good for objects that take optional parameters and objects that need to change their properties many times during their lifecycles.
The bad point is because the objects are publicly exposed it breaks the encapsulation rule of object oriented programming.

IOC – Setter & Getter


Figure: - Getter and Setter

 

In this type of IoC, objects implement a specific interface from the IoC framework, which the IoC framework will use to properly inject the objects.
One of the main advantages of this type is that it doesn't need an external configuration file to configure the object references. Since you need to use the IoC framework's marker interface, the IoC framework knows how to glue the objects together.
The main disadvantage of this approach is that the marker interface ties your application to a specific IoC framework. 

You can see in figure 'Interface based DI' we have implemented an interface 'IAddressDI' which has a 'setAddress' method which sets the address object.
This interface is then implemented in the customer class. External client / containers can then use the 'setAddress' method to inject the address object in the customer object.

IOC – Interface Based


Figure: - Interface based DI



The other way to inject dependency is by using service locator.
Your main class in need to aggregate the child object, will use the service locator to obtain instance of the address object.
The service locator class does not create instances of the address object, it provides a methodology to register and find the services which will help in creating objects.

IOC – Interface Based


Figure: - Service locator




Here we'll see how we can implement DI using 'Programatically' and 'Open Source IoC Framework - Windsor container'

If you are starting a new project, you can choose any of the open source IoC frameworks based on your needs.
If you want to use the IoC pattern in your existing project then you need to write your own classes that support IoC. Though the open source frameworks offer off-the-shelf components and may provide many more features than your own implementation, you can still develop a set of classes that support the IoC pattern using either of the above approach.

Here for example – Constructor Approach.
IOC – Interface Based
interface IAddress
{
   void AddAddress(string address);
}
public class Address : IAddress
{
   public string address;

   public void AddAddress(string address)
   {
      this.address = address;
   }
}

public class ClsCustomer
{
   IAddress address;

   public ClsCustomer(IAddress address)
   {
     this.address = address;
   }

   public string GetAddress()
   {
      Type c = Type.GetType("Address", true, true);
      if (typeof(IAddress).IsAssignableFrom(c))
      {
         return (objAddress as Address).MyAddress;
      }
      return string.Empty;
   }
}

class Client
{
   public void Run()
   {
      IAddress objAddress = new Address();
      objAddress.AddAddress("India");
           
      ClsCustomer customer = new ClsCustomer(objAddress);
      string address = customer.GetAddress();
   }       
}



Ok, now lets see how this will work if we use the Windsor container.

Figure 'Windsor container' shows how it looks like. So

·         Step 1 creates the Windsor container object.
·         Step 2 and 3 register the types (Iaddress) and concrete objects(clsAddress, clsCustomer) in the container.
·         Step 4 requests the container to create the customer object. In this step the container resolves and set the address object in the Constructor.
It's like - ClsCustomer customer = new ClsCustomer(objAddress);
·         Step 5 releases the customer object.
 
IOC – Interface Based


 Figure: - Windsor container 

In actual implementation using the container we never use client code as above, rather we use config files.
You can see from figure 'Creating using config files' we have better flexibility to add more objects. In config file we need to define all the components in the components section.

The XmlInterpreter object helps to read the config file to register the objects in the container.
Using the Container.Resolve method we have finally created the customer object.
So the container plays the mediator role of understanding the Customer object and then injecting the Address object in the customer object through the constructor.

 
IOC – Interface Based

Figure: - Creating using config files


References: Link1, Link2

Hope this helps.

Thanks & Regards,
Arun Manglick