我第一次try 使用WinForms实现MVP方法.

我试图理解每一层的功能.

在我的程序中,我有一个GUI按钮,当点击该按钮时,将打开一个打开文件对话框窗口.

因此,使用MVP,GUI处理按钮单击事件,然后调用presenter.openfile();

在演讲者内部.openfile(),那么它是否应该将该文件的打开委托给模型层,或者由于没有数据或逻辑需要处理,它是否应该简单地根据请求操作并打开openfiledialog窗口?

我决定提供一笔赏金,因为我觉得在这方面我需要进一步的帮助,最好是根据我下面的具体观点量身定做,这样我就有了背景.

好的,在阅读了MVP之后,我决定实现被动视图.实际上,我将在Winform上拥有一组控件,这些控件将由演示者处理,然后将任务委托给模型.我的具体观点如下:

  1. 当winform加载时,它必须获得一个树状视图.因此,我认为视图应该调用一种方法,例如:presenter,这是正确的吗.gettree(),这反过来将委托给模型,模型将获取treeview的数据,创建并配置它,然后将其返回给演示者,演示者将传递给视图,然后视图将简单地将其分配给(比如)一个面板?

  2. 这对Winform上的任何数据控件都一样吗,因为我还有一个datagridview?

  3. 我的应用程序中有许多模型类都具有相同的组件.它还支持一个插件架构,包含需要在启动时加载的插件.视图会简单地调用presenter方法吗?presenter方法会调用加载插件并在视图中显示信息的方法吗?然后哪一层将控制插件引用.视图中是否包含对他们或演示者的引用?

  4. 视图应该处理有关表示的每一件事,从TreeView node colored颜色 到数据网格大小等等,这样的 idea 正确吗?

我认为这是我主要关心的问题,如果我明白这些问题应该如何解决,我想我会没事的.

推荐答案

这是我对MVP和你的具体问题的拙见.

First,用户可以与之交互或只是显示的任何东西都是view.这一观点的规律、行为和特点由一个例子来描述.该界面可以使用WinForms UI、控制台UI、web UI甚至完全没有UI(通常在测试演示者时)来实现——只要遵守视图界面的规则,具体的实现就无关紧要.

Second时,视图始终由presenter控制.这类演讲者的法则、行为和特征也由一个interface描述.该接口对具体的视图实现没有兴趣,只要它遵守其视图接口的规则.

Third,因为演示者控制其视图,为了最小化依赖关系,让视图完全了解其演示者实际上没有任何好处.演示者和视图之间有一个约定的合同,这由视图界面声明.

Third的含义是:

  • 演示者没有视图可以调用的任何方法,但是视图有演示者可以订阅的事件.
  • 演讲者知道自己的观点.我更喜欢通过在混凝土演示器上注入构造函数来实现这一点.
  • 视图不知道是什么演示者在控制它;它永远不会提供给任何演讲者.

对于您的问题,在稍微简化的代码中,上面的代码可能如下所示:

interface IConfigurationView
{
    event EventHandler SelectConfigurationFile;

    void SetConfigurationFile(string fullPath);
    void Show();
}

class ConfigurationView : IConfigurationView
{
    Form form;
    Button selectConfigurationFileButton;
    Label fullPathLabel;

    public event EventHandler SelectConfigurationFile;

    public ConfigurationView()
    {
        // UI initialization.

        this.selectConfigurationFileButton.Click += delegate
        {
            var Handler = this.SelectConfigurationFile;

            if (Handler != null)
            {
                Handler(this, EventArgs.Empty);
            }
        };
    }

    public void SetConfigurationFile(string fullPath)
    {
        this.fullPathLabel.Text = fullPath;
    }

    public void Show()
    {
        this.form.ShowDialog();        
    }
}

interface IConfigurationPresenter
{
    void ShowView();
}

class ConfigurationPresenter : IConfigurationPresenter
{
    Configuration configuration = new Configuration();
    IConfigurationView view;

    public ConfigurationPresenter(IConfigurationView view)
    {
        this.view = view;            
        this.view.SelectConfigurationFile += delegate
        {
            // The ISelectFilePresenter and ISelectFileView behaviors
            // are implicit here, but in a WinForms case, a call to
            // OpenFileDialog wouldn't be too far fetched...
            var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
            selectFilePresenter.ShowView();
            this.configuration.FullPath = selectFilePresenter.FullPath;
            this.view.SetConfigurationFile(this.configuration.FullPath);
        };
    }

    public void ShowView()
    {
        this.view.SetConfigurationFile(this.configuration.FullPath);
        this.view.Show();
    }
}

除上述内容外,我通常还有一个base IView界面,我在其中存放Show()和我的视图通常受益的任何所有者视图或视图标题.

To your questions:

1. When the winform loads, it has to obtain a treeview. Am I correct in thinking that the view should therefore call a method such as: presenter.gettree(), this in turn will delegate to the model, which will obtain the data for the treeview, create it and configure it, return it to the presenter, which in turn will pass to the view which will then simply assign it to, say, a panel?

我会从IConfigurationPresenter.ShowView()IConfigurationView.SetTreeData(...),就在打IConfigurationView.Show()之前

2. Would this be the same for any data control on the Winform, as I also have a datagridview?

是的,我会打IConfigurationView.SetTableData(...).由视图决定给定数据的格式.演示者只需遵守视图的约定,即它需要表格数据.

3. My App, has a number of model classes with the same assembly. It also supports a plugin architecture with plugins that need to be loaded at startup. Would the view simply call a presenter method, which in turn would call a method that loads the plugins and display the information in the view? Which tier would then control the plugin references. Would the view hold references to them or the presenter?

如果插件与视图相关,那么视图应该知道它们,而不是演示者.如果它们都是关于数据和模型的,那么视图就不应该与它们有任何关系.

4. Am I correct in thinking that the view should handle every single thing about presentation, from treeview node colour, to datagrid size, etc?

对可以将其视为提供描述数据的XML的演示者,以及获取数据并对其应用CSS样式表的视图.具体来说,演示者可能会调用IRoadMapView.SetRoadCondition(RoadCondition.Slippery),然后视图会将道路渲染为红色.

What about data for clicked nodes?

5. If when I click on the treenodes, should I pass through the specific node to the presenter and then from that the presenter would work out what data it needs and then asks the model for that data, before presenting it back to the view?

如果可能的话,我会一次性传递在视图中呈现树所需的所有数据.但是,如果一些数据太大,无法从一开始就传递,或者如果它本质上是动态的,需要模型(通过演示者)提供"最新快照",那么我会在视图界面中添加类似于event LoadNodeDetailsEventHandler LoadNodeDetails的内容,以便演示者可以订阅它,从模型中获取LoadNodeDetailsEventArgs.Node中 node 的详细信息(可能是通过其某种ID),以便在事件处理程序委托返回时,视图可以更新其显示的 node 详细信息.请注意,如果获取数据的速度太慢,无法获得良好的用户体验,则可能需要这种异步模式.

.net相关问答推荐

无法在 Blazor Server 应用程序中触发 InputRadio 的 onchange 事件

Visual Studio 2022 中的目标操作系统和目标运行时有什么区别?

EGC / 文本元素上的 .NET String.Split

在接口内部声明 IEnumerable 而在具体类中声明 IList

C#.Net 中的可选返回

您是否使用 TestInitialize 或测试类构造函数来准备每个测试?为什么?

BackgroundWorker 中未处理的异常

如何判断对象是否是某种类型的数组?

什么版本的 .NET 附带什么版本的 Windows?

在 C# 中将匿名类型转换为键/值数组?

如何正确和完全关闭/重置 TcpClient 连接?

Moq - 不可覆盖的成员不能用于设置/验证表达式

ToLowerInvariant() 有什么问题?

让 String.Replace 只打整个单词的方法

嵌套的 Try/Catch 块是个坏主意吗?

绑定在代码隐藏中定义的对象

obj 文件夹是为了什么而生成的?

如何在 C# 中使用迭代器反向读取文本文件

在 IIS 中访问 .svc 文件时出现 HTTP 404

如何在 ASP.NET MVC 中重定向到动态登录 URL