views:

111

answers:

8

Hi

I'm someone who has taught myself programming, and haven't had any formal training in .NET programming.

A while back, I started C# in order to develop a GUI program to control sensors, and the project has blossomed. I was just wondering how best to organise the code, particularly UI code, in my forms.

My forms currently are a mess, or at least seem a mess to me.

  • I have a constructor which initialises all the parameters and creates events.
  • I have a giant State property, which updates the Enabled state of all my form control as users progress through the application (ie: disconnected, connected, setup, scanning) controlled by a States enum.
  • I have 3-10 private variables accessed through properties, some of which have side-effects in changing the values of form elements.
  • I have a lot of "UpdateXXX" functions to handle UI elements that depend on other UI elements - ie: if a sensor is changed, then change the baud rate drop down list. They are separated into regions
  • I have a lot of events calling these Update functions
  • I have a background worker which does all the scanning and analysis.

My problem is this seems like a mess, particularly the State property, and is getting unmaintainable. Also, my application logic code and UI code are in the same file and to some degree, intermingled which seems wrong and means I need to do a lot of scrolling to find what I need.

How do you structure your .net forms?

Thanks

A: 

Here is a link to an architecture pattern used quite often.

http://en.wikipedia.org/wiki/Model_View_ViewModel

I would look up some other Architecture Patterns too, and research more into this one, look up some example code, etc.

Meiscooldude
Personally, I wouldnt use MVVM for a forms application, as it relies heavily on the databinding model that WPF and XAML provides :)
cwap
+1  A: 

Have a look at the Model-View-Presenter patten: http://en.wikipedia.org/wiki/Model_View_Presenter

Using this pattern the code-behind of your forms should mainly contain simple cascading calls to the presenter, which in turn will alter the model, cascading events back to the view (sometimes through the presenter, depending on your implementation).

Point being: Your forms (the view) should not contain any state information; this will be in the presenter, and it should not care about where it gets it data from, as long as the data conforms to a specified contract. This promotes testability, as you can easily test your states and data on the presenter, and decouples the view allowing for PLAFs, different presentations of the same data and similar.

Good luck :)

cwap
I've used an MVC pattern in web development. I'm reading the MVC# doc's linked to from the wiki page, though I can't see how it will work on a complex form.
sb3700
MVC isn't really a feasable option in windows forms as your input/output is tidely connected to a single item (the form). MVP is very different from MVC :)
cwap
+1  A: 

Some quick suggestions:

Try to move all your non-UI code out of the forms, you only want to have GUI code in the actual form if possible. If a property has a side effect it should probably be a function. Your State property should almost certainly be a method and see if you can break out the code out of it into separate methods so it's just the one function call per state.

ho1
It's very convenient having it as a property, as I can go: "if (this.State == States.XXX) ..." or "this.State = States.YYY;". I don't see how changing to a function will help much.Where do I move my UI code to (I think you might mean application code, in which case where do I move that to?).Side effects in my properties are useful - it means I can encapsulate accessing/setting my form elements. Unfortunately, it means I have 10+ properties.
sb3700
@sb3700: Yep, missed the word non in front of UI, you should create separate classes for your non ui code and call them from your UI code when needed (trying to minimize the interface that the UI code can call). I might have misunderstood the State property, I thought you meant that it contained the state machine in there. I agree that it's easy and convenient with side effects, but it makes the code harder to understand since you normally don't assume that a property will have side effects.
ho1
+1  A: 

With complex forms, I usually split the code into separate files. You can do this using "partial class". Each source code file is named based on the form. For example, MainForm.cs, MainForm.State.cs, MainForm.Update.cs, MainForm.Menu.cs and so on. If I have many complex forms, I will create a subfolder for each. The one tip here, is to create a MainForm.Wip.cs form. This partial class form is the code you are currently working on. Once you are done with this code, you can either rename it or move the code to other source code files.

In addition, I will also create user-controls. This has the benefit of code reuse and it moves a lot of the functionality out of the form. Check out "Developing Custom Windows Forms Controls with the .NET Framework" at http://msdn.microsoft.com/en-us/library/6hws6h2t.aspx.

Check out Nobody Cares What Your Code Looks Like at http://www.codinghorror.com/blog/2007/12/nobody-cares-what-your-code-looks-like.html. Something to think about before "organizing".

AMissico
Okay, I never though about using partial classes. Does the .Wip have any significance?
sb3700
Work-In-Progress (wip). No significance. It is just a temporary working partial class source code file. MainForm.Temp really means nothing, but Wip does.
AMissico
I agree with the user controls, but I disagree with splitting the class in partials. I find that that only makes things even harder to understand unless the form is huge, and if the form is that big, I'd say that it should be redesigned to be smaller (for example using user controls). I only like partial classes for generated code.
ho1
Ok. I might have a look in the future, but I don't think custom controls are relevant on the forms I'm developing.
sb3700
I think partial forms might be useful for me in separating application logic stuff from the rest of the UI code.
sb3700
@ho1: Do you want to redesign the application and form just for organization purposes? I hate to sound sarcastic, but I am in the business of making money. If the form works and partial classes help, then use partial classes. That is why Microsoft provide this functionality.
AMissico
@sb3700: You are correct. Moving to partial forms will give you a sense of what can be moved to user-controls, what is specific to the form, and what can be moved into classes.
AMissico
@sb3700: Custom controls are alway relevant. Note that the control doesn't need a user-interface. They call these kinds of controls...components.
AMissico
@sb3700: A class's method can handle a form's event, or a control's event, or any other event. Something to think about.
AMissico
@AMissico: I will have a look at custom controls then. Thanks
sb3700
@AMissico: It all depends on the situation. If the forms is big enough so that it affects my ability to understand and maintain it, then I'd consider a re-design (with re-design I meant the design of the code rather than the GUI) and to try to move the code into user controls or non-ui classes (probably bit by bit), otherwise I'd not change it at all but instead leave exactly as is.
ho1
@AMissico: I think the thing we disagree on though is if partial classes would help, I think not, and I'm also not sure why MS introduced partial classes but I think the main reason they were introduced was to be able to keep *generated* code separately.
ho1
@ho1: I believe we agree in principal. I understand what you meant by re-designing. In this specific case, I think partial classes will teach sb3700 how to organize their code. Which will help to identify what kinds of controls or components are needed, how to separate the logic, and so on. (One foot after the other.)
AMissico
@ho1: Don't forget, sb3700 is self-taught, a newbie, he only wants to organize his code better, so it is easier to maintain.
AMissico
@ho1: The feature was introduced so developers could extend designer-generated code, especially data-sets. The Visual Basic.NET documentation tends to tell developers not to use Partial. The C# documentation tends to recommend the use of partial.
AMissico
@ho1: A form does not have to be huge to have complex UI procesing. I have many forms in my business apps that are comprised of toolstrip, datagridview/ultragridview, and a status bar. Not huge from widget count perspective, but large in processing complexity. I have business objects to remove non-UI code fromthe form. But every type of action that can occur to a business object probably requires a UI response/update. So using partial classes to segregate these impacts makes a lot of sense IMHO. FooFormSave.cs, FooFormValidate.cs, FooFormZZZ.cs, ... make it easy to organzie my code.
cdkMoose
@cdkMoose: I do the same thing. I always have a partial for development stuff; one for the status strip; one for the main toolbar, menu, and wrappers to the actual commands; and so on.
AMissico
@cdkMoose: As I think of it, if the class is big, splitting it up in multiple files doesn't make it easier to understand than to just arrange the code in the one file properly, and you'll have to look for the code in multiple files, but I suppose it's just a matter of preference and as long as all developers in a team do it the same way it doesn't matter too much.
ho1
@ho1: You are right that multiple files does nothing for understanding the code. One other advantage of multiple files is source code management. If I have one developer working on save processing and another working on validation, they are touching separate files and source code control can be applied to their efforts separately.
cdkMoose
A: 

You should analyze your code first to divide what is application logic and what is UI logic. Both of those should never be in the same file. Your state propery is most definitely not UI logic, so move it out of your form first. This will help you clear out your form code.

Secondly, read up about some Design Patterns and principles. You can find some great examples here, in your case I would check out the behavioral patterns, more specifically the State and Mediator pattern. They're not silver bullets to fixing your problems, but it should give you a better idea of how to split your application and UI logic.

KoMet
A: 

I tend to put as much code as possible in usercontrols or custom controls. The components is easier to reuse, and the form-code is easier to read.

Usercontrols can also handle and expose events which can make the dynamic parts easier to seperate from the form code.

You can even make custom controls that can't be seen on the form like a Timer.

Henrik Jepsen
Custom controls without a user-interface, such as the System.Windows.Forms.Timer are called components.
AMissico
+3  A: 

Hi,

There are a number of patterns that help you seperate logic in applications , which results in cleaner and more maintainable code. The MVP pattern is a good one to start with. It is based on defining 3 areas of responisbility i.e. MVP M = Model, V = View, P = Presenter. If you are familiar with using interfaces you will be fine, otherwise that would be a good place to start (review the basic OO priciples: Encapsulation,Abstraction, Polymorphism). The basic principle of the MVP is to put you application logic in the Presenter. The presnter talks to the view (your form) via an interface, and the view calls back to the presenter (i use a interface for this too) when the user interactions with it. The model is the solution's domain object hierarchy which implments buisiness logic and entity relationships.

Most UI patterns (MVP, MCV etc) are trying to do the same things, seperate you concerns. Tghe following is a simple example:

//The view interface

interface IUserDetailsView
{

      string Username{set;get;}
      string FirstName{get;set;}
      string LastName{get;set;}
      UserDetailsPresenter Presenter{get;set;}
      void DisplayMessage(string message);


}

//The view implmentation //A standard windows form which has text boxes, labels, combos etc , which

class UserDetailsView : Form, IUserDetails
{

      public string Username{set{txtUserName.text = value;}get{return txtUserName.text;}}
      public string FirstName{set{txtFirstName.text = value;}get{return txtFirstName.text;}}
      public string LastName{set{txtLastName.text = value;}get{return txtLastName.text;}}

      Public UserDetailsPresenter Presenter{get;set;}

      public void DisplayMaessage(string message)
      {
         MessageBox.Show(message);
      }

      private void saveButton_Click(object sender, EventArgs e)
      {
         Presenter.SaveUserDetails();

      }
}

//Presentation Logic

class Presenter UserDetailsPresenter {

  //Constructor
  public userDetailsPresenter(IUserDetailsView view)
  {
    //Hold a reference to the view interface and set the view's presnter
     _view = view;
     _view.Presenter = this;
  }

  private IUserDetailsView _view;

  DisplayUser(string userName)
  {
     //Get the user from some service ...
     UserDetails details = service.GetUser(userName);

     //Display the data vioa the interface
     _view.UserName = details.UserName;
     _view.FirstName = details.FirstName;
     _view.LastName = details.LastName;

  }

  public void SaveUserDetails()
  {

       //Get the user dryaiols from the view (i.e. the screen
       UserDetails details = new UserDetails();

       details.UserName = _view.UserName;
       details.FirstName = _view.FirstName;
       details.LastName = _view.LastName;

       //Apply some business logic here (via the model)
       if(!details.IsValidUserDetails())
       {
          _view.DisplayMessage("Some detail outlining the issues");
         return;
       }

       //Call out to some service to save the data
       service.UpdateUser(details);

  }

}

//Finally, the model

public class UserDetails
{

   public UserName {get;set;}
   public FirstName{get;set;}
   public LastName{get;set;}

   public bool IsValidUserDetails()
   {
       if(LastName == "Smith")
       {
          //We do not allow smiths, remember what happened last time ... or whatever
          return false;
       }

       return true;
   }

}

Hopefully this explains how responsibility is seperated. The form has no logic apart from display/formatting etc, it can also be stubbed out for testing . The presenter is the mediator between the view and the model and makes calls to services, the model implments your business logic. As already suggested there are variations on this pattern, which can make your code a bit slimmer and more flexible but this outlines the basic principles. I hope this helps.

:-)

NoelAdy
Thanks, an example does help.
sb3700
A: 

I use regions, like this:

#Region "_Edit"
    Private Sub _edit_VisibleChanged(...) Handles _edit.VisibleChanged
    End Sub
#End Region

from top to bottom, my forms code has:

  • private declarations
  • friend properties
  • friend subs
  • private properties
  • private subs
  • events
  • event handlers for private forms/classes

it sounds like your State property needs to be broken up, or maybe have the code moved into other classes or routines so the complexity is more hidden.

Beth
Thanks, I've been using regions as well but it just seemed so ugly.
sb3700