Download Demo
Download Source
Introduction
Even though I have experience writing code using the MVC pattern in other languages such as PHP, Java, etc.,
I came upon a requirement to use MVC for C#/WinForms. When I tried searching for articles and examples of MVC
pattern for C#, I could find quite a number of articles but the simplicity was
missing and most of the articles were written for ASP.NET where MVC is most used. In other words, as part of explaining the MVC pattern, the article/tutorial tries do much more than is required to explain the pattern itself.
Therefore I decided to write this article to explain the implementation of
the MVC pattern with C#/WinForms and keep it as simple as possible.
Background
The Model-View-Controller as it implies contains three components when this model is implemented:
- The Model - This should take care of all the operations which deal with the data required (in other words the business logic) for the application, which is implementing the MVC model from now onwards will be referred to as by
the MVC application. The operations can mean reading, writing data into the database, getting information from remote machines via network, time consuming operations etc. The model should also inform the view about any changes to the data happening in the background.
- The View - This component takes care of presenting the data to the user. With respect to the context of this article, i.e., WinForms, the view class will be tied around with the Form which will be shown to the user.
- The Controller - This is the center and important component of the MVC pattern as it ties the Model and View together. The Model which manipulates the data and the View which presents the data to the user does not know the existence of each other or they
interact directly with each other. It is the controller which acts as an intermediary and ties them together. For example, the controller takes the input from
the user such as a button click and informs the model to take appropriate action, if there should be an action that needs to be initiated to manipulate the project data.
Using the code
Let us take a simple use case of an application which increments the number so as not to divert the reader to get carried away from concentrating on the MVC pattern into the details of other aspects of the project. Exactly, the reason for which I wrote this article. For the sake of simplicity, I did not change the name of the Form or button and left it as is such as button1 and textbox1.
The description of the components
The controller
The controller is the component which does all the work of tying the view and model together. The view does not know about the business logic of how the data is retrieved or handled. Whenever there is an action performed on the view by the user such as a clicking a button or changing a text on the text box it will inform the controller about it. The controller will decide what action needs to be taken based on user input. It might request the model to do some processing of the data after evaluation of the validity of the user input.
namespace MVCTest
{
public interface IController
{
void incvalue();
}
public class IncController : IController
{
IView view;
IModel model;
public IncController(IView v, IModel m)
{
view = v;
model = m;
view.setController(this);
model.attach((IModelObserver)view);
view.changed += new ViewHandler<IView>(this.view_changed);
}
public void view_changed(IView v, ViewEventArgs e)
{
model.setvalue(e.value);
}
public void incvalue()
{
model.increment();
}
}
}
The View
The view class is the component which will really be the Form itself which will implement the View interface.
In the below component it can be seen that the view interface just contains the event handler when the view
is changed and to set the controller, which controls this view.
namespace MVCTest
{
public delegate void ViewHandler<IView>(IView sender, ViewEventArgs e);
public class ViewEventArgs: EventArgs
{
public int value;
public ViewEventArgs(int v) { value = v; }
}
public interface IView
{
event ViewHandler<IView> changed;
void setController(IController cont);
}
}
The Model
The model handles the business logic of incrementing the number passed to it by the controller. It also informs the change in the data value (incremented) to the View. (On the contrary to the statement that, Model does not directly talk to the view, the controller
is the one who ties the model to its view.) The view, i.e., the form, implements the
IModelObserver
which gets invoked (if required) by the model.
namespace MVCTest
{
public delegate void ModelHandler<IModel>(IModel sender, ModelEventArgs e);
public class ModelEventArgs : EventArgs
{
public int newval;
public ModelEventArgs(int v)
{
newval = v;
}
}
public interface IModelObserver
{
void valueIncremented(IModel model, ModelEventArgs e);
}
public interface IModel
{
void attach(IModelObserver imo);
void increment();
void setvalue(int v);
}
public class IncModel : IModel
{
public event ModelHandler<IncModel> changed;
int value;
public IncModel()
{
value = 0;
}
public void setvalue(int v)
{
value = v;
}
public void increment()
{
value++;
changed.Invoke(this, new ModelEventArgs(value));
}
public void attach(IModelObserver imo)
{
changed += new ModelHandler<IncModel>(imo.valueIncremented);
}
}
}
Tying the model-view-controller together
The view class is the component which will really be the Form itself which will implement the View interface.
In the below component it can be seen that the view interface just contains the event handler when the view is changed and sets the controller which controls this view.
namespace MVCTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 view = new Form1();
IModel mdl = new IncModel();
IController cnt = new IncController(view,mdl);
Application.Run(view);
}
}
}
The Form
Finally, the form code which is the real view which implements the setController
function for the
IView
interface and keeps the reference to the controller. For any operation which it needs to perform on the model, it will use the controller to signal it. We can see from the following code that when the button is clicked, it calls the controller to increment the value. When the user types in the textbox, it raises a view changed event which sets the new value into the model via the controller as
the controller has attached to this event from the view. The function implemented,
valueIncremented
, is the implementation
of the interface IModelObserver
which will be invoked by the model whenever a value changes in the model.
namespace MVCTest
{
public partial class Form1 : Form, IView, IModelObserver
{
IController controller;
public event ViewHandler<IView> changed;
public void setController(IController cont)
{
controller = cont;
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
controller.incvalue();
}
public void valueIncremented(IModel m, ModelEventArgs e)
{
textBox1.Text = "" + e.newval;
}
private void textBox1_Leave(object sender, EventArgs e)
{
try
{
changed.Invoke(this, new ViewEventArgs(int.Parse(textBox1.Text)));
}
catch (Exception)
{
MessageBox.Show("Please enter a valid number");
}
}
}
}
Points of Interest
This is my first submission to the CodeProject community. It is interesting
to contribute to CodeProject and I am looking forward to start contributing more and more samples in the area where I have gained experience.
History
- 30 June 2013: Initial draft.
- 02 July 2013: Added demo and source