模型视图演示者事件和关注点分离

时间:2016-08-11 15:13:47

标签: c# .net wpf winforms mvp

我正在构建一个Windows Forms应用程序,我希望将来可能会移植到WPF和GTK#。我有兴趣使用MVP模式来实现这一目标。

对于一个简单的首选项对话框,我有一个设计器创建的表单,它实现了一个视图界面,​​其中包含演示者在保存或关闭对话框时可以监听的事件。我使用设计器在首选项框架的控件和.NET项目设置之间创建数据绑定,所以我正在监督演示者。

interface IPreferencesDialogView
{
    event EventHandler Save;
    event EventHandler Cancel;
}

public partial class PreferencesDialog : Form, IPreferencesDialogView
{
    private PreferencesDialogPresenter presenter = null;

    public event EventHandler Save;
    public event EventHandler Cancel;

    public PreferencesDialog()
    {
        InitializeComponent();

        presenter = new PreferencesDialogPresenter(this);
    }

    private void PreferencesDialog_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (this.DialogResult == DialogResult.OK)
        {
            Save?.Invoke(this, EventArgs.Empty);
        }
        else
        {
            Cancel?.Invoke(this, EventArgs.Empty);
        }
    }
}

我的模型使用.NET项目设置来存储应用程序设置,因为它在Mono中可用,我可以将它与WPF和GTK#一起使用。

class PreferencesDialogPresenter
{
    private readonly IPreferencesDialogView view;

    public PreferencesDialogPresenter(IPreferencesDialogView view)
    {
        this.view = view;

        view.Save += (o, e) => { Properties.Settings.Default.Save(); };
        view.Cancel += (o, e) => { Properties.Settings.Default.Reload(); };
    }
}

在我的主窗体上,我还有一些非常具体的Windows窗体代码,一个级联按钮,级联所有打开的MDI窗口。使用Windows Forms提供的LayoutMdi方法非常简单(Java Swing没有)。

    private void cascade_Click(object sender, EventArgs e)
    {
        this.LayoutMdi(MdiLayout.Cascade);
    }

到目前为止,这对我来说似乎很有效。视图对模型或演示者一无所知,模型对视图或演示者一无所知。但是,我有几个问题。

  • 无论如何都要简化我的活动模式?我真的不想传递我不使用的论据。
  • 理想情况下,我只有一个事件,已关闭,我会将对话框结果转发给演示者。我不喜欢视图中的保存/取消逻辑。但是,DialogResult类型是特定于Windows窗体的,因此我不能将它与GTK#一起使用。我可以创建自己的包装类型吗?那是通常做的吗?
  • 我将如何展示此对话框?例如,在主表单上,我有一个"首选项"菜单项。单击它时,主表单的主持人应该告诉谁打开首选项对话框,它是否应该告诉首选项对话框的视图或演示者自己显示?出现这个问题是因为ShowDialog显然是Windows Forms特有的。
  • 我怎么会把MDI级联逻辑放到我的演示者中,或者在这种情况下甚至不值得打扰?

1 个答案:

答案 0 :(得分:2)

  

有没有简化我的活动模式?我真的不想传递我不使用的参数。

     

理想情况下,我只有一个事件,已关闭,我会将对话框结果转发给演示者。我不喜欢视图中的保存/取消逻辑。但是,DialogResult类型是特定于Windows窗体的,因此我不能将它与GTK#一起使用。我可以创建自己的包装类型吗?这是通常做的吗?

是的,我所做和所相信的最佳做法是创建与发生的操作相关的特定事件。不只是从UI传递事件。因此,单个Close事件包括一个简单的枚举,指示是保存还是取消。您的演示者将包含基于该枚举确定是否要执行Properties.Settings.Default.Save();或Properties.Settings.Default.Reload();

然后在非Windows窗体视图中,您仍然需要调用该事件,但是由视图决定是始终保存还是取消,或者是否实现自定义保存/取消对话框从用户那里获取此信息。