29

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?

5 Answers 5

27

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.

8

I personally prefer to separate different areas of concern between several assemblies instead of bundling everything together into a single executable.

Typically, I prefer to keep an absolute minimal quantity of code in the application's entry point - No business logic, no GUI code and no data access (databases/file access/network connections/etc); I usually limit the entry point code (i.e. the executable) to something along the lines of

  • Creating and Initialising the various application components from all of the dependent assemblies
  • Configuring any 3rd party components which the whole application depends on (e.g. Log4Net for diagnostic output)
  • also I'll probably include a "catch all exceptions and record the stack trace" type bit of code in the main function which will help log the circumstances of any unforseen critical/fatal failures.

As for the application components themselves, I usually aim for at least three in a small application

  • Data Access Layer (database connections, file access, etc) - depending on the complexity of any persistant/stored data used by the application, there might be several of these assemblies - I probably would create a separate assembly for database handling (Possibly even multiple assemblies if interacting with the database involved anything complex - e.g. if you're stucx with a badly designed database, you may need to handle DB relationships in code, therefore it might make sense to write multiple modules for insertion and retrieval)

  • Logic Layer - the main "meat" containing all of the decisions and algorithms which make your application work. These decisions should know absolutely nothing about the GUI (who says there's a GUI?), and should know absolutely nothing about the database (Huh? There's a database? why not a file?). A well-designed logic layer can hopefully be "ripped out" and dropped into another application without needing to be re-compiled. In a complicated application, there might be a whole bunch of these logic assemblies (because you may just want to rip out 'pieces' without dragging along the rest of the application)

  • Presentation layer (i.e. the GUI); In a small application, there might just be a single "main form" with a couple of dialog boxes which can all go into a single assembly - in a bigger application, there might be separate assemblies for whole functional parts of the GUI. The classes here will do little more than make the user interaction work - it'll be little more than a shell with some basic input validation, handling any animation, etc. Any events/button clicks which "do something" will be passed forward to the logic layer (so my presentation layer will strictly contain no application logic whatsoever, but it will also not place the burden of any GUI code on the logic layer either - so any progress bars or other fancy stuff will also sit in the presentation assembly/ies)

My main rationale for splitting the Presentation, Logic and Data layers to separate assemblies is this: I feel that it's preferable to be able to run the main application logic without your database or your GUI.

To put it another way; if I want to write another executable which behaves in exactly the same way as your application, but uses a commandline interface, or a web interface; and swaps the database storage for file storage (or a different kind of database maybe), then I can do so without needing to touch the main application logic at all - all I'd need to do is write a little a command-line tool and another data model, then "plug it all together", and I'm ready to go.

You may be thinking "Well I'm never going to want to do any of that so it doesn't matter if I can't swap these things around" - the real point is that one of the hallmarks of a modular application is the ability to extract 'chunks' (Without needing to re-compile anything), and re-use those chunks elsewhere. In order to write code like this, it generally forces you to think long and hard about design principles - You'll need to think about writing a lot more interfaces, and think carefully about the trade-offs of various S.O.L.I.D principles (In the same way as you would for Behaviour-Driven-Development or TDD)

Sometimes achieving this separation from an existing monolithic lump of code is a little painful and requires a lot of careful refactoring - that's OK, you should be able to do it incrementally - you may even reach a point where there are too many assemblies and you decide to go back the other way and start wrapping things up together again (going too far in the opposite direction can have the effect of making those assemblies rather useless on their own)

4

As per the folder structure, what you suggested is OK in general. You may need to add folders for resources (sometimes people create resources such that each set of resources are grouped under an ISO language code to support several-languages), images, database scripts, user preferences (if not dealt with as resources), fonts, external dlls, local dlls, etc.

What is the naming convention when adding classes?

Of course, you want to separate each class outside the form. I would recommend also, a file per class (although MS does not do that in code generated for EF for example).

Many people use meaningful short nouns in plural (e.g. Customers). Some ptrfer the name to be close to the singular name for the corresponding database table (if you use 1-1 mapping between objects and tables).

For naming classes there are many sources, for example take a look at:.net Naming Conventions and Programming Standards - Best Practices and/or STOVF-C# Coding Guidelines

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

Helper code should go to one or more helper classes. Other code that very common to GUI controls such as applying user preferences to a grid, could be removed from the form and either added to helper classes or by sub classing the control in question and creating the necessary methods there.

Due to the event-action nature of MS Windows Forms, there is nothing that I know of that could help you take away code from the main form without adding ambiguity and effort. However, MVVM may be a choice (in future projects), see for example: MVVM for Windows Forms.

2

Consider MVP as an option because it will help you organize presentation logic, which is everything in large business applications. In real life, app logic resides mostly in the database, so rarelly you have the need for actual write a business layer in native code, leaving it only with the need to have well structured presentation functionality.

MVP-like structure will result in a set of presenters, or controllers if you prefer, that will coordinate with each other and will not mix with UI or code behind stuff. You could even use different UIs with same controller.

Finally, simple organizing resources, decoupling components and specifying depedencies with IoC and DI, along with an MVP approach will provide you with the keys for building a system that avoids common mistakes and complexity, is delivered in time and is open for changes.

1

The structure of a project totally depends on the Project and its size, however you can add few folders e.g.

  • Common (Containing classes e.g. Utilities)
  • DataAccess (classes related to access of data using sql or any other database server your using)
  • Styles (If you got any CSS files in your project)
  • Resources (e.g. Images, resource files)
  • WorkFlow (Classes related to workflow if you have any)

You dont need to put Forms into any kind of folder, just rename your forms accordingly. I mean its common sense no one knows what name should be your forms better then yourself.

Naming convention is like if your class printing a "Hello World" message then class name should be something related to the task and class's appropriate name should HelloWorld.cs.

you can create regions as well e.g.

#region Hello and then out endregion at the end.

You can create classes for tabs, am pretty sure you can, and one last thing is reuse your code where possible, best practice is to make methods and use them again where needed.

Books ? erm.

There's no books tell you the structure of projects as each project is different, you learn these kind of things by experience.

Hope it helped!

Not the answer you're looking for? Browse other questions tagged or ask your own question.