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

本文关键字:关注点 分离 事件 视图 模型 | 更新日期: 2023-09-27 18:01:52

我正在构建一个Windows窗体应用程序,我希望将来有可能将其移植到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窗体提供的LayoutMdi方法非常简单(Java Swing没有)。

    private void cascade_Click(object sender, EventArgs e)
    {
        this.LayoutMdi(MdiLayout.Cascade);
    }
到目前为止,这对我来说似乎工作得很好。视图对模型或呈现者一无所知,而模型对视图或呈现者一无所知。但是,我有几个问题。
  • 是否有办法简化我的事件模式?我真的不喜欢传递我不使用的参数。
  • 理想情况下,我将只有一个事件,Closed,我将把对话结果转发给演示者。我不喜欢视图中的保存/取消逻辑。但是,dialgresult类型是特定于Windows窗体的,所以我不能在gtk#中使用它。我可以创建自己的包装器类型吗?这是通常的做法吗?
  • 我该如何显示这个对话框?例如,在主表单上,我有一个"Preferences"菜单项。当它被单击时,主表单的演示者应该告诉谁打开首选项对话框,它应该告诉首选项对话框的视图还是演示者显示自己?出现这个问题是因为ShowDialog显然是Windows窗体特定的。
  • 我该如何将MDI级联逻辑放入演示器中,或者在这种情况下甚至不值得费心?

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

是否有办法简化我的事件模式?我真的不喜欢传递我不使用的参数。

理想情况下,我将只有一个事件Closed,并将对话框结果转发给演示者。我不喜欢视图中的保存/取消逻辑。但是,dialgresult类型是特定于Windows窗体的,所以我不能在gtk#中使用它。我可以创建自己的包装器类型吗?这是通常的做法吗?

是的,我所做和相信的是最佳实践是创建与正在发生的操作相关的特定事件。不仅仅是从UI传递事件。因此,单个Close事件包括一个简单的枚举来指示是保存还是取消。演示器将包含基于该enum确定是否执行Properties.Settings.Default.Save()的逻辑;

或Properties.Settings.Default.Reload ();

然后在你的非Windows窗体视图,你仍然需要调用该事件,但它将由视图来决定是否保存或取消所有的时间,或者是否实现自定义保存/取消对话框从用户获取此信息。