Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Your first program using MVC pattern with C#/WinForms

0.00/5 (No votes)
2 Jul 2013 1  
A simple example of using the MVC pattern with C#/WinForms.

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.

MVC illustration for C# Forms

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
{
    // The Icontroller supports only one functionality that is to increment the value
    public interface IController
    {
        void incvalue();
    }
    public class IncController : IController
    {
        IView view;
        IModel model;
        // The controller which implements the IController interface ties the view and model 
        // together and attaches the view via the IModelInterface and addes the event
        // handler to the view_changed function. The view ties the controller to itself.
        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);
        }
        // event which gets fired from the view when the users changes the value
        public void view_changed(IView v, ViewEventArgs e)
        {
            model.setvalue(e.value);
        }
        // This does the actual work of getting the model do the work
        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);
    // The event arguments class that will be used while firing the events
    // for this program, we have only one value which the user changed.
    public class ViewEventArgs: EventArgs 
    {
        public int value;
        public ViewEventArgs(int v) { value = v; }
    }
    // Currently, the interface only contains the method to set the controller to which
    // it is tied. The rest of the view related code is implemented in the form.
    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);
    // The ModelEventArgs class which is derived from th EventArgs class to 
    // be passed on to the controller when the value is changed
    public class ModelEventArgs : EventArgs
    {
        public int newval;
        public ModelEventArgs(int v) 
        { 
            newval = v; 
        }
    }
    // The interface which the form/view must implement so that, the event will be
    // fired when a value is changed in the model.
    public interface IModelObserver
    {
        void valueIncremented(IModel model, ModelEventArgs e);
    }
    // The Model interface where we can attach the function to be notified when value
    // is changed. An actual data manipulation function increment which increments the value
    // A setvalue function which sets the value when users changes the textbox
    public interface IModel
    {
        void attach(IModelObserver imo);
        void increment();
        void setvalue(int v);
    }
    public class IncModel : IModel
    {
        public event ModelHandler<IncModel> changed;
        int value;
        // implementation of IModel interface set the initial value to 0
        public IncModel() 
        { 
            value = 0; 
        }
        // Set value function to set the value in case if the user directly changes the value
        // in the textbox and the view change event fires in the controller
        public void setvalue(int v) 
        { 
            value = v; 
        } 
        // Change the value and fire the event with the new value inside ModelEventArgs
        // This will invoke the function valueIncremented in the model and will be displayed
        // in the textbox subsequently
        public void increment() 
        { 
            value++; 
            changed.Invoke(this, new ModelEventArgs(value));
        }
        // Attach the function which is implementing the IModelObserver so that it can be
        // notified when a value is changed
        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
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            // Create the View, Model and Controller object yourself. 
            // Create a controller object with the concreate implementation IncController 
            // and pass the view and model.
            // Controller will store its associated model and view inside the constructor
            // View which is inside the form will tie the controller automatically
            // Run the view object created by you which is infact the form
            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
{
    // Form is reallly the view component which will implement the IModelObserver interface 
    // so that, it can invoke the valueIncremented function which is the implementation
    // Form also implements the IView interface to send the view changed event and to
    // set the controller associated with the view
    public partial class Form1 : Form, IView, IModelObserver
    {
        IController controller;
        public event ViewHandler<IView> changed;
        // View will set the associated controller, this is how view is linked to the controller.
        public void setController(IController cont)
        {
            controller = cont;
        }
        
        public Form1()
        {
            InitializeComponent();
        }
        // when the user clicks the button just ask the controller to increment the value
        // do not worry about how and where it is done
        private void button1_Click(object sender, EventArgs e)
        {
            controller.incvalue();
        }
        // This event is implementation from IModelObserver which will be invoked by the
        // Model when there is a change in the value with ModelEventArgs which is derived
        // from the EventArgs. The IModel object is the one from which invoked this.
        public void valueIncremented(IModel m, ModelEventArgs e)
        {
            textBox1.Text = "" + e.newval;
        }
        // When this event is raised can mean the user must have changed the value.
        // Invoke the view changed event in the controller which will call the method
        // in IModel to set the new value, the user can enter a new value and the
        // incrementing starts from that value onwards
        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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here