Question

I'm trying to use the Model-View-Controller-Pattern in my new project, a Windows Forms C# Application. I have my project split into several sub-projects:

Core
UI (View)
Controller
Model
Services
Helper
Tests

The project dependecies are as follows: Project Dependencies (generated by Visual Studio

My UI-Project contains 2 Forms, ListForm and AddForm (there are other forms, but these are not relevant for this question).

  • In the Controller-Project, I have interfaces for the different forms, which the Controller uses for updating the View.

  • In the Core-Project, I initialize a new ListForm, Controller and Model.

Now, if the User clicks the Add-Button inside the ListForm, I want the AddForm to Show. But how can I create a new instance of AddForm inside the Controller if the Controller doesn't even know the UI-Project?

I tried to use a Service, but since the Service had to know the UI-Project to create instances, I would have had a circular dependency (according to Visual Studio).

How can I show the AddForm if the Users clicks the Add-Button inside the ListForm? (There is always max. 1 AddForm shown at a Time).

Was it helpful?

Solution

One of possible approaches involves a controller factory. The factory is responsible for creating controllers and views and wiring both together.

The factory should be configurable so you could have different implementations for differnt set of views - a set of views that is used to build an actual ui has its own factory, another test set has another factory etc. All factories are accessed through the same api so that you only reconfigure the factory when necessary. One of the possible ways to implement such factory would be to use an IoC container, it could simplify the implementation but it is not necessary. With the IoC container you would just register different implementations of your views and could reuse the same implementation of the factory whereas without the IoC container you would need an extra implementation of the factory for each set of views.

Then your parent controller creates an instance of the child controller using the factory. The factory returns the child controller with the proper view injected into it. The parent controller calls the ShowView on the child controller which just makes the view visible or the child controller could even show the view automatically upon creation.

Edit: the example factory that creates controllers/views:

In the controller layer:

public interface IControllerFactory
{
    TController CreateControllerAndView<TController>()
         where TController : Controller;
}

public class ControllerFactory
{
    // actual provider
    private static IControllerFactory _provider;

    // factory method
    public static TController
        CreateControllerAndView<TController>() where T : Controller
    {
        return _provider.CreateController<TController>();
    }

    public static void SetProvider( IControllerFactory provider )
    {
        _provider = provider;
    }
}

Anytime you want to create a new controller, you refer to the factory:

var controller = ControllerFactory.CreateControllerAndView<UserController>();

Note that the factory doesn't depend on anything, it is merely defined, not yet implemented.

Then, somewhere in the most upper layer, in the startup project probably, you implement a concrete provider:

public class ConcreteControllerFactory : IControllerFactory
{
    public TController CreateControllerAndView<TController>()
    {
        // since you are in the top most layer, you know all types from
        // underlaying layers, including controllers and views

        // IoC would help here a lot! But without it:

        if ( typeof<TController> == typeof<UserController> )
        {
            IUserView view = new UIUserView();
            UserController c = new UserController( view );
        }
        ...
    }
}

and then somewhere

ControllerFactory.SetProvider( new ConcreteControllerFactory() );

This way you can plug any specific provider to the factory, the test provider, the ui provider, whatever. The actual implementation could vary but you should get the idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top