如何构建C#WinForms模型 - 视图 - 演示者(被动视图)程序?

时间:2010-12-01 22:24:28

标签: c# winforms design-patterns mvp passive-view

我正在设计一个具有以下基本概念的GUI(类似地模仿Visual Studio的基本外观):

  1. 文件导航
  2. 控制选择器(用于选择在编辑器组件中显示的内容)
  3. 编辑
  4. 记录器(错误,警告,确认等)
  5. 目前,我将使用TreeView进行文件导航,使用ListView选择要在编辑器中显示的控件,使用RichTextBox进行Logger。编辑器将具有两种类型的编辑模式,具体取决于TreeView中选择的内容。编辑器将是一个RichTextBox,用于手动编辑文件内的文本,或者它将是一个带有拖放DataGridViews和子文本框的面板,用于在此面板中进行编辑。

    我试图遵循被动视图设计模式,将模型与视图完全分离,反之亦然。这个项目的本质是我添加的任何组件都需要编辑/删除。因此,我需要从给定控件到下一个控件的独立性。如果今天我使用TreeView进行文件导航,但明天我被告知要使用其他东西,那么我想要相对容易地实现一个新的控件。

    我根本不明白如何构建程序。我理解每个Control的一个Presenter,但我不知道如何使它工作,以便我有一个View(程序的整个GUI)和控件(子视图),这样整个视图是可替换的以及个人反映我的模型的控件。

    在主视图中,Passive View标准应该是轻量级的,我是否单独实现子视图?如果是这样,请说我有一个接口INavigator来抽象导航器对象的角色。导航器需要Presenter和Model才能在Navigator View和主View之间进行操作。我觉得我迷失在某处的设计模式术语中。

    可以找到最相似的问题here,但它没有详细回答我的问题。

    有人请帮助我理解如何“构建”这个程序吗?我感谢任何帮助。

    谢谢,

    丹尼尔

2 个答案:

答案 0 :(得分:23)

答案 1 :(得分:4)

我知道这个问题差不多有两年了,但我发现自己情况非常相似。像你一样,我已经在互联网上搜索了DAYS而没有找到符合我需求的具体例子 - 我搜索得越多,我就越来越多地一遍又一遍地回到同一个地方,我得到了大约10页的紫色Google中的链接!

无论如何,我想知道你是否想出了一个令人满意的问题解决方案?根据我上周阅读的内容,我将概述到目前为止我是如何做到的:

我的目标是: 被动形式,首先是演示者(演示者实例化表单,因此表单不知道它的演示者) 通过在表单(视图)中引发事件来调用演示者中的方法

该应用程序有一个FormMain,其中包含2个用户控件:

ControlsView(有3个按钮) DocumentView(第三方图像缩略图查看器)

“主窗体”包含一个工具栏,用于保存通常的文件等等。 “ControlsView”用户控件允许用户单击“扫描文档” 它还包含一个树视图控件,用于显示文档和页面的层次结构 “DocumentView”显示扫描文档的缩略图

我觉得每个控件都应该拥有自己的MVP三元组,以及主要形式,但我希望它们都能引用相同的模型。我无法弄清楚如何协调控件之间的沟通。

例如,当用户点击“扫描”时,ControlsPresenter负责从扫描仪获取图像,我希望它将页面添加到树视图中,因为每个页面都是从扫描仪返回的 - 没问题 - 但我也是希望缩略图同时出现在DocumentsView中(主持人彼此不了解的问题)。

我的解决方案是让ControlsPresenter调用模型中的方法将新页面添加到业务对象中,然后在模型中引发“PageAdded”事件。

然后我让ControlsPresenter和DocumentPresenter“监听”此事件,以便ControlsPesenter告诉它将视图添加到树视图,并且DocumentPresenter告诉它添加新缩略图的视图。

总结:

控制视图 - 引发事件“ScanButtonClicked”

控制Presenter - 听到事件,按如下方式调用Scanner类到AcquireImages:

GDPictureScanning scanner = new GDPictureScanning();

IEnumerable<Page> pages = scanner.AquireImages();
foreach (Page page in pages)
{
m_DocumentModel.AddPage(page);                
//The view gets notified of new pages via events raised by the model
//The events are subscribed to by the various presenters so they can 
//update views accordingly                
}

扫描每个页面时,扫描循环调用“yield return new Page(PageID)”。 上面的方法调用m_DocumentModel.AddPage(page)。 新页面将添加到模型中,从而引发事件。 两者都控制演示者和文档演示者“听到”事件并相应地添加项目。

我不确定的是所有演示者的初始化 - 我在Program.cs中这样做如下:

static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

IDocumotiveCaptureView view = new DocumotiveCaptureView();
IDocumentModel model = new DocumentModel();
IDocumotiveCapturePresenter Presenter = new DocumotiveCapturePresenter(view, model);
IControlsPresenter ControlsPresenter = new ControlsPresenter(view.ControlsView, model);
IDocumentPresenter DocumentPresenter = new DocumentPresenter(view.DocumentView, model);

Application.Run((Form)view);                                                         
}

不确定这是好,坏或无动于衷!

无论如何,对于一个两年前的问题来说,这是一篇很重要的帖子 - 尽管可以获得一些反馈......