Как управлять несколькими формами в MVC-Pattern

Я пытаюсь использовать Model-View-Controller-Pattern в моем новом проекте, приложении Windows Forms C#. Мой проект разделен на несколько подпроектов:

Core
UI (View)
Controller
Model
Services
Helper
Tests

Зависимости проекта следующие: Зависимости проекта (сгенерированные Visual Studio

Мой UI-проект содержит 2 формы, ListForm и AddForm (есть другие формы, но они не имеют отношения к этому вопросу).

  • В Контроллер-Проекте у меня есть интерфейсы для различных форм, которые Контроллер использует для обновления Представления.

  • В базовом проекте я инициализирую новый ListForm, Controller и Model.

Теперь, если пользователь нажимает кнопку добавления внутри ListForm, я хочу, чтобы AddForm показывал. Но как я могу создать новый экземпляр AddForm внутри Контроллера, если Контроллер даже не знает UI-Project?

Я пытался использовать Сервис, но так как Сервис должен был знать UI-Project для создания экземпляров, у меня была бы круговая зависимость (согласно Visual Studio).

Как я могу показать AddForm, если Пользователи нажимают кнопку Add внутри ListForm? (Всегда отображается максимум 1 AddForm).

1 ответ

Решение

Один из возможных подходов связан с фабрикой контроллеров. Фабрика отвечает за создание контроллеров и представлений, а также за соединение проводов.

Фабрика должна быть настраиваемой, чтобы у вас могли быть разные реализации для разных наборов представлений - набор представлений, который используется для создания реального пользовательского интерфейса, имеет свою собственную фабрику, другой набор тестов имеет другую фабрику и т. Д. Все фабрики доступны через один и тот же API. так что вы можете перенастроить фабрику только при необходимости. Одним из возможных способов реализации такой фабрики было бы использование контейнера IoC, это могло бы упростить реализацию, но в этом нет необходимости. С контейнером IoC вы просто регистрируете различные реализации ваших представлений и можете повторно использовать одну и ту же реализацию фабрики, тогда как без контейнера IoC вам потребуется дополнительная реализация фабрики для каждого набора представлений.

Затем ваш родительский контроллер создает экземпляр дочернего контроллера, используя фабрику. Фабрика возвращает дочерний контроллер с соответствующим видом, введенным в него. Родительский контроллер вызывает ShowView на дочернем контроллере, который просто делает вид видимым, иначе дочерний контроллер может даже автоматически отобразить вид при создании.

Редактировать: пример фабрики, которая создает контроллеры / представления:

На уровне контроллера:

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;
    }
}

Каждый раз, когда вы хотите создать новый контроллер, вы обращаетесь к фабрике:

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

Обратите внимание, что фабрика ни от чего не зависит, она просто определена, но еще не реализована.

Затем, где-то на самом верхнем уровне, в проекте запуска, возможно, вы реализуете конкретный поставщик:

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 );
        }
        ...
    }
}

а потом где-то

ControllerFactory.SetProvider( new ConcreteControllerFactory() );

Таким образом, вы можете подключить к фабрике любого конкретного провайдера, провайдера тестирования, провайдера пользовательского интерфейса и т. Д. Реальная реализация может отличаться, но вы должны понять.

Другие вопросы по тегам