views:

2507

answers:

6

Hi

My first try of MVC. Am trying to implement a simple example. Inspiration from here. Have I got this pattern (yet!)?

  1. View: "Hey, controller, the user just told me he wants the first person"

  2. Controller: "Hmm, having checked his credentials, he is allowed to do that... Hey, model, I want you to get me the first person"

  3. Model: "First person... got it. Back to you, Controller."

  4. Controller: "Here, I'll collect the new set of data. Back to you, view."

  5. View: "Cool, I'll show the first person to the user now."

View:

namespace WinFormMVC
{
    public partial class Form1 : Form
    {
        controller cont = new controller();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = cont.checkPermissionsAndGetFirstPerson();
        }
    }
}

Controller:

public class controller
    {
        public string checkPermissionsAndGetFirstPerson()
        {
            string returnValue = "";
            if (checkPermissions())
            {
                model m = new model();
                returnValue =  m.getFirstPerson();
            }

            return returnValue;

        }

        public bool checkPermissions()
        {
            return true;
        }
    }

Model:

public class model
    {
        public string getFirstPerson()
        {
            return "Bill Smith";
        }
    }
A: 

Your checkPermissionsAndGetFirstPerson method is probably doing too much. Authorization and fetching data should probably be separate operations.

Also, if your Form1 class is your view, it probably shouldn't be constructing the controller. That seems backwards.

Most information you'll find on MVC in .NET will be for ASP.NET MVC web applications. You might want to check out the WinFormsMVC project on CodePlex to see how someone else has tackled this problem.

http://winformsmvc.codeplex.com/

Here's another WinForms MVC implementation on CodePlex. Looks like it's got a bit more documentation.

http://koosserymvcwin.codeplex.com/

Dennis Palmer
Ahhh.. Yes, the Form1 class is my view. So if shouldn't be constructoring the controller, how should it work? This is just what I'm trying to understand :-)
Dave
+1  A: 

Hmm... I am not sure if I'd call this MVC... As with ASP.NET WebForm, this form is more like an MVP pattern.

As per my understanding, in MVC, controller is the one responsible for managing all resources and flow of the code. In your example, you basically creating a Windows Form first (the view) and then attach a controller to it which is more of a MVP sort of things.

In a classical MVC pattern, the Model, once instantiated, will be linked to the View and when the model changes, the view will get notified (possibly through Observer / PubSub pattern).

Button click, etc. from the View will be routed to the controller which will coordinate those sort of stuffs.

see: this.

Jimmy Chandra
Jimmy - many thanks.. How would I instantiate the model in this example?
Dave
Win Form comes with program.cs. You can instantiate your controller class in there and ask it to create your view perhaps? :)
Jimmy Chandra
Cheers Jimmy...have tried this.. getting issues referencing the controller from the view if its created in program.cs.. hmm could you demo a bit of code please?
Dave
Hmm... the code example is going to be a bit long, so look it up at http://cid-9ce3c99ed4a9933e.skydrive.live.com/self.aspx/.Public/Simple.MVC.Example.zip.It's basically your example modified to fit my "view" of what MVC might look like in a WinForm environment. Some of the code can be improved (i.e. not threadsafe), but for simple example sake, I'm omitting those. It will also demonstrate how View and Model interact through Pub/Sub / eventing. This is a VS2010 solution, you might need to convert it to VS2008 first. I'm using some .NET 3.5 stuffs, so it won't run on VS2005.
Jimmy Chandra
Other things to note: Program.cs, I was instantiating a controller there and pass along its view to the Application.Run (that is expecting a Form instance).I usually put common interface in a common location (dll) to break circular references, but again for simplicity, I didn't do it in this example. Instead, all interfaces are places inside a folder structure to align the namespaces. Forgot to move them into the Common folder.Notice that Employee class provide an event so any code that might be interested in any property changes can get notified (pub/sub/observer)
Jimmy Chandra
Don't pay too much attention to line 79 (MonitorChanges) and the rest of the stuffs (up to line 103) in Employee.cs. There are there to just simulate constant update to the model in the example.
Jimmy Chandra
In TopEmployeeForm.cs, notice line 31 where I'm registering that this particular view is interested in any changes that is going to happen in the model (Employee) and specify what method to run when such change occurs. There are ways to clean up UpdateView method a bit, but I'll leave it up to you to research. This is normal way to prevent threading violation in Windows UI.Notice as well that the form is inheriting an interface called ITopEmployeeView (to further abstract the view from Windows Form for testability). You found this often also in MVP pattern.
Jimmy Chandra
Jimmy - many thanks for your code and comments... really appreciated. I've been sidetracked by an MVP implementation (aptly named Noddy implementation) which was a bit simpler. So I tried that first and am updating my blog on www.programgood.net with my understanding. Have compiled and ran your app.. which I'm going to try and explain in the same style..ie a big picture and in English. Hope this will help others in the future.Cheers againDave.
Dave
Glad to help :)
Jimmy Chandra
Hi Jimmy.. Have put first shot of explaining your code on my blog... http://www.programgood.net/2009/07/17/SimpleMVCInWinForms.aspx
Dave
A: 
James
Cheers James.. am getting the theory (I think).. just trying to get working code now!
Dave
I think by the looks of your question example you do understand how it is meant to work and the relationship between the view/controller and model. The easiest example you could probably do is create a basic view whether it be a form/web page or whatever and place a label and a button. Then create a controller class that will handle the click event of the button. Then create a model class that will simply return a string indicating the button was pressed. So the process should be User -> Click Button -> Controller -> Tells Model -> Model does something -> View -> Updates itself.
James
So really what you are looking to do is make the Model implement ISubject (review the Subject pattern) and the View to implement IObserver (review the Observer pattern). The model should then implement a method called Update which will inform all the observers (which in this instance would be the view) when a significant change has occurred. These changes should contain some sort of reference (perhaps the data/object that has been updated) and an indicator defining what sort of change has occurred i.e. (UserDeleted, UserAdded, UserUpdated). Hope that helps.
James
A: 

You might find this tutorial very helpful: http://nerddinnerbook.s3.amazonaws.com/Intro.htm. Written by Scott Guthrie, it explains the MVC workflow very well. Part 4 should have the basics you're looking for.

synhershko
Thanks synhershko.. am trying to build up the simplest implementation first, so can then go and use frameworks.
Dave
Not sure what you mean by "frameworks". That tutorial will guide you through Models, Views and Controllers, explaining all the basics while building a simple application. MVC and ASP.NET are the only frameworks used there (and LINQ as a tool, but that's optional - you can use standard DALs instead if necessary).
synhershko
+1  A: 

I would describe MVC more like this:

  1. Request (MVC url routing, some event passed from previous UI etc)

  2. Controller - check credentials, get data, return Model

  3. Model - represents the data passed back from the Controller

  4. View - render the Model returned by the Controller. Depending on the Model may display UI to initialise new Controller actions. May also pass Model back to next Controller action.

I think it can be a little confused because in many Model implementations (such as Linq) they provide data definition and access, but it's still the Controller that knows where to start (even if it's the Model that knows how to save its own changes).

So, your code should be something like:

//Controller:
public class PersonController
{
    public PersonAction Detail(int personId)
    {
        Person returnValue;
        //get person from DB and populate returnValue
        return new PersonAction( returnValue );
    }
}

//Model:
public class Person
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
}

//View:
public partial class PersonDetailView : MVCForm<Person>
{
    public Form1( Person model ):base(model) {
        textBox1.Text = model.FirstName + " " + model.LastName;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        textBox1.Text = model.FirstName + " " + model.LastName;
    }
}

What this example is missing is the framework that makes this all possible - there are two significant parts to that:

  1. Something that takes/parses parameters and based on that calls a controller's action method. For instance in Asp.net MVC this is the routing handlers - the call above would be the request url: ~/Person/Detail/personId

  2. Something that takes the result from the action (PersonAction in the example above) and finds the correct view to display. In this example it would open a PersonDetailView form and pass the Person model to it.

There are lots of example frameworks for an MVC implementation for WinForms - one of them may be a good starting point.

Keith
Hi Keith.. many thanks. Have been playing with your code, however haven't quite understood yet, nor got it working. What would be ideal is if you could fill out the code above into something that would compile. My brain hurts.. great fun trying to get this :-)
Dave
A: 

I think there are a few corrections to be made to your narrative. Strinctly speaking the view does not contact the controller, the user contacts the controller directly. In a web app it looks like this.

  1. User: Hey web app, can I have the resource at /people/1

  2. Routing engine: That means you person controller. get the first user.

  3. User controller: Model, I need you to get me user record for the authenticated user, and the person record for the first person.

  4. User Controller: Right. I know the authenticated user is an admin, and person one does exist. So return the Admin view for person to the user.

  5. Rendering engine: Build up the html from the view (template) and person object (data)

This is difficult to do in webforms. I guess the best way is to have a page for each controller, and have that page dynamiclly choose and display a user control. One for each view. It is important in MVC that the view is dumb. All requests are handled directly by controllers, which then select which view to use.

Jack Ryan
JayArr.. thanks. Am actually more interested in the web side of things.. went with webforms to make things simpler (grin). If you've got time to put a super simple demo of MVC in asp.net that shows the concept and flow of data that would be awesome. Not using a framework :-)
Dave