c# - WinForms 中的模型 View 展示器

标签 c# .net winforms design-patterns mvp

我第一次尝试使用 WinForms 实现 MVP 方法。

我正在尝试了解每一层的功能。

在我的程序中,我有一个 GUI 按钮,单击该按钮会打开一个打开文件对话框窗口。

所以使用MVP,GUI处理按钮点击事件,然后调用presenter.openfile();

在 presenter.openfile() 中,是否应该将该文件的打开委托(delegate)给模型层,或者因为没有要处理的数据或逻辑,它是否应该简单地响应请求并打开 openfiledialog 窗口?

更新:我决定悬赏,因为我觉得在这方面我需要进一步的帮助,最好是根据我下面的具体要点量身定制,以便我了解背景。

好的,在阅读了 MVP 之后,我决定实现被动 View 。实际上,我将在 Winform 上拥有一堆控件,这些控件将由 Presenter 处理,然后将任务委托(delegate)给 Model(s)。我的具体观点如下:

  1. 当 winform 加载时,它必须获得一个 TreeView 。我是否正确认为 View 因此应该调用一个方法,例如:presenter.gettree(),这反过来将委托(delegate)给模型,模型将获取 TreeView 的数据,创建它并配置它,将它返回给presenter,它又会传递给 View ,然后 View 将它简单地分配给一个面板?

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

  3. 我的应用程序有许多具有相同程序集的模型类。它还支持带有需要在启动时加载的插件的插件架构。 View 是否会简单地调用一个呈现器方法,而该方法又会调用一个加载插件并在 View 中显示信息的方法?哪一层将控制插件引用。 View 是否包含对他们或演示者的引用?

  4. 我认为 View 应该处理与表示有关的每一件事,从 TreeView 节点颜色到数据网格大小等,我的想法是否正确?

我认为它们是我主要关心的问题,如果我了解这些的流程应该如何,我想我会没事的。

最佳答案

这是我对 MVP 和您的具体问题的谦虚看法。

首先,用户可以与之交互或仅显示的任何内容都是 View 。这种 View 的规律、行为和特征由接口(interface)描述。该界面可以使用 WinForms UI、控制台 UI、Web UI 甚至根本没有 UI 来实现(通常在测试演示者时)——具体的实现并不重要,只要它遵守其 View 界面的规则.

其次, View 始终由演示者 控制。这种演示者的规律、行为和特征也由接口(interface)描述。该接口(interface)对具体的 View 实现不感兴趣,只要它遵守其 View 接口(interface)的规则即可。

第三,因为演示者控制它的 View ,为了最小化依赖性,让 View 完全了解它的演示者真的没有任何好处。在演示者和 View 之间有一个约定的契约(Contract),并由 View 界面声明。

第三的含义是:

  • Presenter 没有任何 View 可以调用的方法,但 View 具有 Presenter 可以订阅的事件。
  • 演示者知道自己的观点。我更喜欢通过在具体演示者上注入(inject)构造函数来完成此操作。
  • View 不知道哪个演示者在控制它;它永远不会提供给任何演示者。

对于您的问题,上面的代码在某种程度上可能看起来像这样:

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

除上述之外,我通常有一个基本的 IView 接口(interface),我在其中存储 Show() 和我的 View 通常从中受益的任何所有者 View 或 View 标题.

您的问题:

1. 当 winform 加载时,它必须获得一个 TreeView 。我是否正确认为 View 因此应该调用一个方法,例如:presenter.gettree(),这反过来将委托(delegate)给模型,模型将获取 TreeView 的数据,创建它并配置它,将它返回给presenter,它又会传递给 View ,然后 View 将它简单地分配给一个面板?

I would call IConfigurationView.SetTreeData(...) from IConfigurationPresenter.ShowView(), right before the call to IConfigurationView.Show()

2. 这对于 Winform 上的任何数据控件是否相同,因为我也有一个 datagridview?

Yes, I would call IConfigurationView.SetTableData(...) for that. It's up to the view to format the data given to it. The presenter simply obeys the view's contract that it wants tabular data.

3. 我的应用程序有许多模型类具有相同的程序集。它还支持带有需要在启动时加载的插件的插件架构。 View 是否会简单地调用一个呈现器方法,而该方法又会调用一个加载插件并在 View 中显示信息的方法?哪一层将控制插件引用。 View 是否包含对它们或演示者的引用?

If the plugins are view-related, then the views should know about them, but not the presenter. If they are all about data and model, then the view shouldn't have anything to do with them.

4. 我认为 View 应该处理与表示有关的每一件事,从 TreeView 节点颜色到数据网格大小等,我的想法是否正确?

Yes. Think about it as the presenter providing XML that describes data and the view that takes the data and applies a CSS stylesheet to it. In concrete terms, the presenter might call IRoadMapView.SetRoadCondition(RoadCondition.Slippery) and the view then renders the road in red color.

点击节点的数据呢?

5. 如果当我点击树节点时,我是否应该将特定节点传递给演示者,然后演示者会从中计算出它需要什么数据,然后询问该数据的模型,然后再将其呈现回 View ?

If possible, I would pass all data needed to present the tree in a view in one shot. But if some data is too large to be passed from the beginning or if it's dynamic in its nature and needs the "latest snapshot" from the model (via the presenter), then I would add something like event LoadNodeDetailsEventHandler LoadNodeDetails to the view interface, so that the presenter can subscribe to it, fetch the details of the node in LoadNodeDetailsEventArgs.Node (possibly via its ID of some kind) from the model, so that the view can update its shown node details when the event handler delegate returns. Note that async patterns of this might be needed if fetching the data might be too slow for a good user experience.

关于c# - WinForms 中的模型 View 展示器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4794121/

相关文章:

c# 加载C文件,然后将其转换为Assembly

c# - 如何忽略 String.ToUpper() 中的撇号?

c# - 多线程并行阶乘

c# - .Net framework 到底有多跨平台?

c# - 如何使用 Task.Wait 避免 WinForm 卡住

c# - 根据以前的 XML 组合框选择填充组合框

c# - 如何使用 C# 从 XML 中删除所有 namespace ?

c# - 什么是 Control.Disposing 属性?

c# isBackground 线程未正确终止

c# - 枚举和字典<枚举, Action >