views:

214

answers:

5

i'm trying to wrap my head around how to enterprise up my code: taking a simple routine and splitting it up into 5 or 6 methods in 3 or 4 classes.

i quickly came up three simple examples of code how i currently write it. Could someone please convert these into an MVC/MVP obfuscated version?


Example 1: The last name is mandatory. Color the text box red if nothing is entered. Color it green if stuff is entered:

private void txtLastname_TextChanged(object sender, EventArgs e)
{
   //Lastname mandatory. 
   //Color pinkish if nothing entered. Greenish if entered.
   if (txtLastname.Text.Trim() == "")
   {
      //Lastname is required, color pinkish
      txtLastname.BackColor = ControlBad;
   }
   else
   {
      //Lastname entered, remove the coloring
      txtLastname.BackColor = ControlGood;
   }
}

Example 2: The first name is optional, but try to get it. We'll add a bluish tint to this "try to get" field:

private void txtFirstname_TextChanged(object sender, EventArgs e)
{
    //Firstname can be blank.
    //Hint them that they should *try* to get it with a bluish color.
    //If they do enter stuff: it better be not all spaces.
    if (txtFirstname.Text == "")
    {
       //Nothing there, hint it blue
       txtFirstname.BackColor = ControlRequired;
    }
    else if (txtFirstname.Text.Trim() == "")
    {
       //They entered spaces - bad user!
       txtFirstname.BackColor = ControlBad;
    }
    else
    {
       //Entered stuff, remove coloring
       txtFirstname.BackColor = SystemColors.Window;
    }
}

Example 3 The age is totally optional. If an age is entered, it better be valid:

private void txtAge_TextChanged(object sender, EventArgs e)
{
   //Age is optional, but if entered it better be valid
   int nAge = 0;
   if (Int32.TryParse(txtAge.Text, out nAge))
   {
      //Valid integer entered
      if (nAge < 0)
      {
         //Negative age? i don't think so
         txtAge.BackColor = ControlBad;
      }
      else
      {
         //Valid age entered, remove coloring
         txtAge.BackColor = SystemColors.Window;
      }
   }
   else
   {
      //Whatever is in there: it's *not* a valid integer,
      if (txtAge.Text == "")
      {
         //Blank is okay
         txtAge.BackColor = SystemColors.Window;
      }
      else
      {
         //Not a valid age, bad user
         txtAge.BackColor = ControlBad;
      }
   }
}

Every time i see MVC code, it looks almost like random splitting of code into different methods, classes, and files. i've not been able to determine a reason or pattern to their madness. Without any understanding of they why it's being one some way, it makes no sense. And using the words model, view, controller and presenter, like i'm supposed to know what that means, doesn't help.

The model is your data.

The view shows data on screen.

The controller is used to carry out the users actions

And oranges taste orangy.


Here's my attempt at splitting things up in order to make the code more difficult to follow. Is this anywhere close to MVC?

private void txtFirstname_TextChanged(object sender, EventArgs e)
{
   FirstnameTextChangedHandler(sender, e);
}

private void FirstnameTextChangedHandler(sender, e)
{
   string firstname = GetFirstname();

   Color firstnameTextBoxColor = GetFirstnameTextBoxColor(firstname);

   SetFirstNameTextBoxColor(firstnameTextBoxColor);
}

private string GetFirstname()
{
   return txtFirstname.Text;
}

private Color GetFirstnameTextBoxColor(string firstname)
{
    //Firstname can be blank.
    //Hint them that they should *try* to get it with a bluish color.
    //If they do enter stuff: it better be not all spaces.
    if (firstname == "")
    {
       //Nothing there, hint it blue
       return GetControlRequiredColor();
    }
    else if (firstname.Trim() == "")
    {
       //They entered spaces - bad user!
       return GetControlBadColor();
    }
    else
    {
       //Entered stuff, remove coloring
       return GetControlDefaultColor();
    }
}

private Color GetControlRequiredColor()
{
   return ControlRequired;
}

private Color GetControlBadColor()
{
   return ControlBad;
}

private Color GetControlGoodColor()
{
   return ControlGood;
}
//am i doin it rite

i've obfuscated the code, but it's still altogether. The next step in the MVC obfuscation, i gather, is to hide the code in 3 or 4 different files.

It's that next step that i don't understand. What is the logical separation of which functions are moved into what other classes? Can someone translate my 3 simple examples above into full fledged MVC obfuscation?


Edit: Not ASP/ASP.NET/Online. Pretend it's on a desktop, handheld, surface, kiosk. And pretend it's language agnostic.

A: 

Most of what you doing in your code belongs to the Controller class since it describes the the logic. Your View should just describe UI and give easy access to UI components. Model class should describe your data model.

The idea is simple: Controller does everything, but it has to know about the View and the Model. For example as View is initialized, Controller sets up all the logic ( kinda what you already doing). As Model is assigned to the Controller - it sets the values into appropriate UI controls and does the same to retrieve data and return is as Model.

So basically you give your data model class to the controller, it does the editing and returns your data as model class again.

eugener
What is the difference between a "controller" or "presenter" raising a change event from a text box, and WinForms doing it? WinForms is handling the presentation, they're just sending me events that i can then use to drive the view. Isn't the Form a presenter, and i'm the controller?
Ian Boyd
A: 

It would be very hard to follow MVC in classic ASP.NET if possible, so I will reply based on MVP.

On your first example, you are trying to do a validation. Validating a surname is the responsibility of Presenter. Showing the field red is the responsibility of View. So, your view class would be like this:

private void Page_Load()
{
    this._presenter = new Presenter();
}

private void txtLastname_TextChanged(object sender, EventArgs e)
{
    txtLastName.BackColor = presenter.IsLastnameValid(txtLastName.Text) ?
        ControlGood : ControlBad;
}

And your presenter class would be something like this:

public Presenter()
{
    public bool IsLastNameValid(string lastname)
    {
        return string.IsNullOrEmpty(lastname);
    }
}

Last name is your model here.

Please note that I prepared this classes only for showing how would you form an MVP structure. In real world, there are lots of better ways to do validation. Normally you would use this approach for your business instead of validation.

Serhat Özgel
Can you expand on what some better ways to do validation might be? Also, when you say "this approach" do you mean my approach, your approach, other the 'better' approaches? Finally what do you mean when you say "this" approach would be better for your business than validation? Is it the validation that is bad? Is validation bad?
Ian Boyd
+1  A: 

The main idea I have when implementing MVC for Windows Forms is that I want to have unit tests for my model and my controller. In order to achieve that, my controller should not know anything about the views using it, and so any notifications that should be handled on UI level are implemented as events. In your example, my controller would look something like this:

class Controller
{
    // This is the model we are operating on
    private Model model_;

    public enum Status
    {
        Normal,
        Required,
        Good,
        Bad
    }

    public delegate void FirstNameStatusChangedDelegate(Status newStatus);
    public event FirstNameStatusChangedDelegate FirstNameStatusChangedEvent;

    public string FirstName
    {
        get { return model_.FirstName; }
        set
        {
            if (value == "")
                RaiseFirstNameStatusChanged(Status.Required);
            else if ( value.Trim() == "" )
                RaiseFirstNameStatusChanged(Status.Bad);
            else
            {
                model_.FirstName = value;
                RaiseFirstNameStatusChanged(Status.Normal);
            }
        }
    }

    private void RaiseFirstNameStatusChanged(Status newStatus)
    {
        if ( FirstNameStatusChangedEvent != null )
            FirstNameStatusChangedEvent(newStatus);
    }
}

And the view would provide handlers for the FirstNameStatusChanged event:

class View : Form
{
    private Controller controller_;
    private static readonly Dictionary<Controller.Status, Color> statusColors_ = new Dictionary<Controller.Status, Color>
    {
        {Controller.Status.Normal, SystemColors.Window},
        {Controller.Status.Required, ControlRequired},
        {Controller.Status.Good, ControlGood},
        {Controller.Status.Bad, ControlRed}
    };

    public View(Controller controller)
    {
        InitializeComponent();
        controller_ = controller;

        contoller_.FirstNameStatusChangedEvent += OnFirstNameStatusChanged;
    }

    private void txtFirstname_TextChanged(object sender, EventArgs e)
    { controller_.FirstName = txtFirstName.Text; }

    private void OnFirstNameStatusChanged(Controller.Status newStatus)
    { txtFirstName.BackColor = statusColors_[newStatus]; }
}
Bojan Resnik
You answered what i asked for, but man it makes my eyes glaze over.
Ian Boyd
This approach is quite different from the common "throw it all inside the form", but I find the code implemented according to MVC much more readable and much easier to understand, let alone test and verify.
Bojan Resnik
+1  A: 

The purpose of MVC/MVP patterns is not obfuscation, but separation of concerns. Obfuscation is to (conceal the) intended meaning in communication, making communication confusing, intentionally ambiguous, and more difficult to interpret: ref. The use of patterns is to make the code cleaner and more understandable. I suggest you start out by reading the wikipedia entries on MVC and MVP.

Both patterns are ways of structuring your code so that your application is broken up into elements that carry out specific purposes that have clearly defined interaction boundaries. Rather than having code that specifically addresses business concerns, input/output handling, and presentation throughout the various classes of the application, these concerns are separated and isolated in the various architectural components. These architectural elements are insulated from one another by the interaction boundaries (interfaces) making them more independent of one another and easier to modify without affect the application as a whole.

tvanfosson
i've read the wikipedia entries. Purchased the GoF book, a book on design patterns in C#, read the original papers on MVC in smalltalk, and read numerous web articles and blogs.
Ian Boyd
If you've already done all that, then what you need to do is put something together with it, do some coding. Honestly, it sounds like you're over-thinking this.
Robert Harvey
@Robery Harvey: Each time i start, i get stymied at Step #1: making a model, or view, or controller. i need practical examples.
Ian Boyd
A: 
Robert Harvey
i'm not using the web. Pretend it's language agnostic computer code.
Ian Boyd