Model view controller is a classic pattern that is used in applications that need ability to maintain multiple views with same data. It can be used as an architectural pattern as well as a design pattern. MVC helps us to decouple the presentation layer and business layer (domain logic layer). The presentation layer is further divided into the View and Controller.
The MVC abstraction can be graphically explained as given below:
The main participants are
Model: The business entity/ domain data on which the application operates. Many applications use a persistent storage mechanism (such as a database) to store data. MVC does not specifically mention the data access layer because it is understood to be underneath or encapsulated by the Model.
View: The user interface that renders the model into a form of interaction.
Controller: Handles a request from a view and updates the model resulting a change in Model’s state.
To implement MVC in .NET we need mainly three classes (View, Controller and the Model). This example is implemented using interfaces that will allow me to make my application loosely coupled.
I have the interfaces (IView, IModel, IController) implemented as
public interface IView
{
//Method to change the state of view according to the model changes
void UpdateView(IModel model);
//These methods are used by the controller to change the state of view
void SalaryIncreased(Boolean increased);
void CompanyChanged(Boolean changed);
void DesignationChanged(Boolean changed);
}
public interface IModel
{
String UserName { get; set; }
String Company { get; set; }
String Designation { get; set; }
Int32 Salary { get; set; }
//Implementing the observer pattern. The model uses an observer
//pattern implementation to notify the views about the changes in the
//model
void AddObserver(IView view);
void RemoveObserver(IView view);
void Notify();
//Observer pattern implementation methods. End
}
public interface IController
{
//The methods to change the state of Model
void ChangeSalary(Int32 salary);
void ChangeCompany(String company);
void ChagneDesignation(String designation);
//Storing the Model and View instances in the controller
IModel Model { get; set; }
IView View { get; set; }
}
In my sample application I have a User class (Model) and a Form that helps users to change the User properties (View). I also have a UserController class that acts as a controller for the View.
The model
public class User: IModel
{
private String userName;
private String company;
private String designation;
private Int32 salary;
//List of observers. You can add the views that should be notified the change on Model in this
//collection.
List<IView> observers = new List<IView>();
public User() { }
public User(String userName, String company, String designation, Int32 salary)
{
this.userName = userName;
this.company = company;
this.designation = designation;
this.salary = salary;
}
#region IModel Members
public string UserName
{
get
{
return this.userName;
}
set
{
this.userName = value;
}
}
public string Company
{
get
{
return this.company;
}
set
{
this.company = value;
this.Notify();
}
}
public string Designation
{
get
{
return this.designation;
}
set
{
this.designation = value;
this.Notify();
}
}
public int Salary
{
get
{
return this.salary;
}
set
{
this.salary = value;
this.Notify();
}
}
//Adding the View into the Observer collection
public void AddObserver(IView view)
{
observers.Add(view);
}
public void RemoveObserver(IView view)
{
if (observers.Contains(view))
observers.Remove(view);
}
//Iterates through the observers and notify them about the model change.
public void Notify()
{
foreach (IView view in observers)
{
view.UpdateView(this);
}
}
#endregion
}
The View
public partial class UserView : Form, IView
{
//The controller instance for the View.
private IController Controller = new UserController();
//Creating a model. (Sample).
private IModel Model = new User("Arun", "EDS", "Tech Lead", 50000);
public UserView()
{
InitializeComponent();
//Wire the controller and model to the View
WireUpControllerModel(Model, Controller);
//Update the View with the model's current state
this.UpdateView(Model);
}
private void _companycomboBox_SelectedIndexChanged(object sender, EventArgs e)
{
Controller.ChangeCompany(_companycomboBox.Text);
}
private void _designationComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
Controller.ChagneDesignation(_designationComboBox.Text);
}
private void _changeSalaryButton_Click(object sender, EventArgs e)
{
Controller.ChangeSalary(Convert.ToInt32(_newSalaryTextBox.Text));
}
#region IView Members
public void UpdateView(IModel model)
{
_userNameTextBox.Text = model.UserName;
_designationTextBox.Text = model.Designation;
_companyTextBox.Text = model.Company;
_salaryTextBox.Text = model.Salary.ToString();
}
private void WireUpControllerModel(IModel model, IController controller)
{
if (Model != null)
Model.RemoveObserver(this);
Model = model;
Controller = controller;
Controller.Model = this.Model;
Controller.View = this;
Model.AddObserver(this);
}
public void SalaryIncreased(bool increased)
{
if (increased)
_salaryChangeLabel.Text = "Salary Increased!!!";
else
_salaryChangeLabel.Text = "Salary Decreased!!!";
}
public void CompanyChanged(bool changed)
{
if (changed)
_companyChangeLabel.Text = "Company Changed!!!";
}
public void DesignationChanged(bool changed)
{
if (changed)
_designationChangeLabel.Text = "Designation Changed!!!";
}
#endregion
}
The controller:
public class UserController : IController
{
private IView view;
private IModel model;
public UserController(IView view, IModel model)
{
this.view = view;
this.model = model;
}
public UserController() { }
#region IController Members
public void ChangeSalary(int salary)
{
if (Model.Salary > salary)
View.SalaryIncreased(false);
else
View.SalaryIncreased(true);
Model.Salary = salary;
}
public void ChangeCompany(string company)
{
if (Model.Company == company)
View.CompanyChanged(false);
else
View.CompanyChanged(true);
Model.Company = company;
}
public void ChagneDesignation(string designation)
{
if (Model.Designation == designation)
View.DesignationChanged(false);
else
View.DesignationChanged(true);
Model.Designation = designation;
}
public IModel Model
{
get
{
return this.model;
}
set
{
this.model = value;
}
}
public IView View
{
get
{
return this.view;
}
set
{
this.view = value;
}
}
#endregion
}