【问题标题】:How to manage multiple forms in MVC-Pattern如何在 MVC-Pattern 中管理多个表单
【发布时间】:2013-12-08 13:00:43
【问题描述】:

我正在尝试在我的新项目(一个 Windows 窗体 C# 应用程序)中使用 Model-View-Controller-Pattern。 我将我的项目拆分为几个子项目:

Core
UI (View)
Controller
Model
Services
Helper
Tests

项目依赖如下:

我的 UI-Project 包含 2 个表单,ListForm 和 AddForm(还有其他表单,但这些与此问题无关)。

  • 在 Controller-Project 中,我有不同表单的接口,控制器用于更新视图。

  • 在 Core-Project 中,我初始化了一个新的 ListForm、Controller 和 Model。

现在,如果用户单击 ListForm 内的 Add-Button,我希望 AddForm 显示。 但是,如果 Controller 甚至不知道 UI-Project,我如何在 Controller 中创建 AddForm 的新实例?

我尝试使用 Service,但由于 Service 必须知道 UI-Project 才能创建实例,因此我会有循环依赖(根据 Visual Studio)。

如果用户单击 ListForm 内的 Add-Button,我如何显示 AddForm? (每次最多显示 1 个 AddForm)。

【问题讨论】:

标签: c# winforms forms model-view-controller circular-dependency


【解决方案1】:

其中一种可能的方法涉及控制器工厂。工厂负责创建控制器和视图并将它们连接在一起。

工厂应该是可配置的,因此您可以对不同的视图集有不同的实现 - 用于构建实际 ui 的一组视图有自己的工厂,另一个测试集有另一个工厂等。所有工厂都可以通过相同的 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() );

通过这种方式,您可以将任何特定的提供者插入工厂、测试提供者、ui 提供者等等。实际实现可能会有所不同,但您应该明白这一点。

【讨论】:

  • 我需要把这个工厂放在哪个项目中以避免循环依赖。另外,我以前没有使用过“父控制器”。你能解释一下你的意思吗(我有一些想法,但我不知道它是否正确)?
  • 工厂应该在你的控制器和ui接口被定义的项目中定义。工厂的具体提供者应该在你的“组合根”中实现,即你的解决方案的主项目。 “父控制器”是指与父(主)视图关联的控制器,与“子”控制器相反,它与您将要创建的表单相关联。
  • 我知道什么是工厂,但是工厂的提供者是什么,它是做什么的?
  • 工厂提供者是你工厂的具体实现。这就像 mvc 的控制器工厂 - 您可以在 Composition Root 中设置具体实现,同时能够在较低层定义工厂本身并从那里引用它。如果您需要代码,请告诉我,但对于聪明人来说,这个词可能就足够了。
  • 我非常感谢一个代码示例,因为这是我使用 MVC 的第一个项目(除了一个小型测试项目)而且我还没有使用过工厂。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多