.NET – How to Properly Structure a Project in WinForms

netproject-structurevisual studiowinforms

A while ago I started to create a winform application and at that time it was small and I did not give any thought of how to structure the project.

Since then I added additional features as I needed and the project folder is getting bigger and bigger and now I think it is time to structure the project in some way, but I am not sure what is the proper way, so I have few questions.

How to properly restructure the project folder?

At the moment I am thinking of something like this:

  • Create Folder for Forms
  • Create Folder for Utility classes
  • Create Folder for Classes that contain only data

What is the naming convention when adding classes?

Should I also rename classes so that their functionality can be identified by just looking at their name? For example renaming all forms classes, so that their name ends with Form.
Or is this not necessary if special folders for them are created?

What to do, so that not all the code for main form ends up in Form1.cs

Another problem I encountered is that as the main form is getting more massive with each feature I add, the code file (Form1.cs) is getting really big.
I have for example a TabControl and each tab has bunch of controls and all the code ended up in Form1.cs. How to avoid this?

Also, Do you know any articles or books that deal with these problems?

Best Answer

It looks like you've fallen into some of the common pitfalls, but don't worry, they can be fixed :)

First you need to look at your application a little differently and start breaking it down into chunks. We can split the chunks in two directions. First we can separate controlling logic (The business rules, data access code, user rights code,all that sort of stuff) from the UI code. Second we can break the UI code down into chunks.

So we'll do the latter part first, breaking the UI down into chunks. The easiest way to do this is to have a single host form on which you compose your UI with usercontrols. Each user control will be in charge of a region of the form. So imagine your application had a list of users, and when you click on a user a text box below it is filled with their details. You could have one user control managing the display of the user list and a second one managing the display of the user's details.

The real trick here is how you manage the communication between the controls. You don't want 30 user controls on the form all randomly holding references to each other and calling methods on them.

So you create an interface for each control. The interface contains the operations the control will accept and any events it raises. When you think about this app, you don't care if the list box list selection changes, you are interested in the fact a new user has changed.

So using our example app, the first interface for the control hosting the listbox of users would include an event called UserChanged which passes a user object out.

This is great because now if you get bored of the listbox and want a 3d zoomy magic eye control, you just code it to the same interface and plug it in :)

Ok, so part two, separating the UI logic from the domain logic. Well, this is a well worn path and I'd recommend you look at MVP pattern here. It's really simple.

Each control is now called a View (V in MVP) and we've already covered most of what is needed above. In this case, the control and an interface for it.

All we're adding is the model and the presenter.

The model contains the logic that manages your application state. You know the stuff, it would go to the database to get the users, write to the database when you add a user, and so on. The idea is you can test all of this in complete isolation from everything else.

The Presenter is a bit more tricky to explain. It is a class which sits between the model and the View. It is created by the view and the view passes itself into the presenter using the interface we discussed earlier.

The presenter doesn't have to have its own interface, but I like to create one anyway. Makes what you want the presenter to do explicit.

So the presenter would expose methods like ListOfAllUsers which the View would use to get its list of users, alternatively, you could put an AddUser method the View and call that from the presenter. I prefer the latter. That way the presenter can add a user to the listbox when ever it wants.

The Presenter would also have properties like CanEditUser, which will return true if the user selected can be edited. The View will then query that every time it needs to know. You might want editable ones in black and read only ones in Gray. Technically that's a decision for the View as it is UI focused, whether the user is editable in the first place is for the Presenter. The presenter knows because it talks to the Model.

So in summary, use MVP. Microsoft provide something called SCSF (Smart Client Software Factory) which uses MVP in the way I've described. It does a lot of other things too. It's quite complex and I don't like the way they do everything, but it may help.

Related Topic