使用MVP加载子视图

时间:2009-06-30 11:05:39

标签: c# winforms mvp

过去几天我一直在使用winforms玩MVP模式,只有一件事我不知道该怎么办。如何从另一个视图创建子窗体。这是一个有效的选择。

 public class MyForm : IMainFormView
    {
        private MainFormPresenter pres;
        public MyForm() { pres = new MainFormPresenter(this); }

        //Event from interface.
        public event EventHandler<EventArgs> LoadSecondForm;

        public void SomeButtonClick()
        {
            LoadSecondForm(this, EventArgs.Empty);
        }
    }

    public class MainFormPresenter
    {
        private IMainFormView mView;

        public MainFormPresenter(IMainFormView view) {
            this.mView = view;
            this.Initialize();
        }

        private void Initialize() {
            this.mView.LoadSecondForm += new EventHandler<EventArgs>(mView_LoadSecondForm);
        }


        private void mView_LoadSecondForm(object sender, EventArgs e) {
            SecondForm newform = new SecondForm(); //Second form has its own Presenter.
            newform.Load(); // Load the form and raise the events on its presenter.
        }
    }

我主要关注的是如何使用此模式加载子表单,以及如何将第一页中的ID称为子表单。

感谢。

3 个答案:

答案 0 :(得分:8)

http://www.rickardnilsson.net/post/The-Humble-dialog-v2.aspx

上面的链接是我见过的最接近这个的链接。解决这个问题的大多数尝试都有待改进。

答案 1 :(得分:2)

看看this other SO question。虽然它与WPF有关,而与WinForms无关,但问题似乎是一样的。

基本上,我认为需要向辅助窗口显示一个服务(您可以将其称为WindowsService或DialogService或类似的东西)。这有助于您对事物进行透视,因为只要您意识到这一点,依赖注入就成为了答案。

在你的回答中,你用事件建模,但我更喜欢一个更明确的模型,你调用DialogService的ShowDialog方法。但是,每种方法的机制都没有那么不同。

答案 2 :(得分:1)

对此有几点评论

首先这个

    private void mView_LoadSecondForm(object sender, EventArgs e) {
        SecondForm newform = new SecondForm(); //Second form has its own Presenter.
        newform.Load(); // Load the form and raise the events on its presenter.
    }

如果您决定将ThirdForm替换为SecondForm,会发生什么?您需要找到newform = new SecondForm的每个调用并进行更改。

相反,您应该在命令对象中包装SecondForm的创建

   public class CreateSecondForm : ICommand
    {

        public void Execute() {
            SecondForm newform = new SecondForm(); //Second form has its own Presenter.
            newform.Load(); // Load the form and raise the events on its presenter.
        }

    }

然后在这里和任何其他地方出现第二种形式使用此语法

private void mView_LoadSecondForm(object sender, EventArgs e) {
    CreateSecondForm createCmd = new CreateSecondForm(); 
    createCmd.Execute(); // Load the form and raise the events on its presenter.
}

如果你想为SecondForm替换一个全新的表单,那么你只需要一个地方。如果要传入状态或设置值,请使用命令的构造函数。您甚至可以传入另一个Presenter或View,并让命令从其界面中提取信息。

我建议的另一件事是您注册实现视图的表单而不是使用新命令。这是在初始化期间完成的,并且注册表会挂起主应用程序类。

例如。

public class MySecondForm : ISecondFormView, IViewForm
    {
        //Stuff ....
       Public ViewFormEnum ViewFormType {
          return ViewFormEnum.SecondForm;
       }
        //Stuff ....
    }

软件中的其他地方

public void InitializeApp() {
        //Stuff ....
        MyApp.ViewForm.Add(new MySecondForm);

        //Stuff ....

}

然后命令设置如下。

   public class CreateSecondForm : ICommand
    {
        myApp theApp;
        public CreateSecondForm(myApp thisApp) {
           theApp = thisApp;
        }

        public void Execute() {
            SecondForm newform = theApp.Find(ViewFormEnum.SecondForm);
            if (newForm != null) 
               newform.Load(); // Load the form and raise the events on its presenter.
        }

    }

原谅我的C#它不是我的主要语言。这种方法的优点是包含表单的程序集可以换出具有不同表单集的不同程序集。这对于自动化测试特别有用,可以在其中创建模拟类而不是表单。您还可以将其设置为处理空视图,这对于释放完整应用程序的子集非常有用。

虽然我强烈建议您使用该命令来包装视图的创建。根据申请,注册View的第二个建议可能过度。在我的CAD / CAM应用程序中,我有几十个对话框和几种不同的主要形式,用于设置和控制2D金属切割台的不同方面。然而,在我公司的一些其他应用程序中,我使用一种简单的方法,因为它们大多是简单的实用程序。