使用Windows窗体实现MVC


102

在哪里可以找到一个很好的示例,说明如何在Windows窗体中完全实现MVC模式?

我在各个站点(例如,The Code Project和.NetHeaven)上找到了许多教程和代码示例,但是与MVC相比,它们在观察者模式方面更具代表性。由于我要开发的应用程序是用于学校项目的,因此我不愿意使用诸如PureMVCMVC#之类的框架。



Answers:


115

我认为应用程序之间有很大的不同,我们对应如何编写应用程序的理解仍然非常有限。我以前处理过的Windows Forms应用程序彼此之间有很大不同。我看到的一些设计差异是(包括大多数组合):

  • 直接与数据库对话(2层)
  • 使用已为给定应用程序编写的后端(3层)
  • 使用为许多应用程序编写的一组Web服务,这些Web服务不能为您的应用程序更改。(面向服务的体系结构)
  • CRUD操作正在完成更新
  • 使用命令模式进行更新(将命令发送到后端服务器)
  • 大量使用数据绑定 /没有使用数据绑定
  • 大多数数据都是“表式”的(例如发票),在标准网格控件中运行良好/需要针对大多数UI数据的自定义控件。
  • 一个开发人员/由10或20个开发人员组成的团队(仅在用户界面上)
  • 使用模拟等进行大量单元测试/没有单元测试

因此,我认为不可能创建一个始终适合的MVC(或MVP)实现。

我见过的真正能解释 MVC以及为什么要以这种方式构建MVC系统的最佳文章是Jeremy D Miller撰写“ Build Your Own CAB”系列。工作之后,您应该能够更好地理解您的选择。 还应该考虑Microsoft的智能客户端指南(CAB / Microsoft复合应用程序块)。它有点复杂,但是可以很好地适合于应用程序。

为Winforms项目选择MVC / MVP实现将提供值得阅读的概述。很多人喜欢PureMVC。我从未使用过它,但是下一次我需要MVC框架时会考虑它。

Presenter First ”是一种软件开发方法,结合了Model View Presenter(MVP)设计模式和测试驱动开发的思想。它使您可以通过以客户的语言编写测试开始。例如:

“当我单击“保存”按钮时,应保存文件,而未保存的文件警告应消失。”

我没有使用“ Presenter First”的经验,但是如果有机会,我会尝试一下,因为它看起来非常有前途。

您可能希望查看的其他堆栈溢出问题在此处此处

如果您想在任何时候使用WPF,请看一下Model-View ViewModel(MVVM)模式。这是一个非常不错的视频,您应该看一下:Model-View-ViewModel上的Jason Dolinger

Winforms的MVVM(模型视图视图模型)设计模式提供了另一个选项,可以在需要时使其更容易转换为WPF。 Magical.Trevor是Windows窗体的另一个MVVM示例,还包括基于属性名称的自动绑定。


还问自己为什么使用MVC。

  • 您是否希望能够对尽可能多的代码进行单元测试?
  • 您是否在尝试允许尽可能多的代码被重用?
  • 您是否正在尝试使代码库易于理解?
  • 101个可能对给定项目有效的其他原因。

一旦确定了目标,选择一种实现或另一种实现就变得更加容易。


@ AgnelKurian,CAB是Microsoft提供的有关如何构建应用程序的一组示例代码-现在它已成为历史。
伊恩·林格罗斯

哈哈!是的,我现在记得那些“应用程序块”。
Agnel Kurian13年

45

更新:除了下面我以前的回答,我建议阅读有关“ Presenter First”方法的信息(尤其是PDF文章)

我建议使用MVP(实际上是PassiveView模式)而不是MVC。您实际上并不需要任何特殊的框架,这只是您组织代码的方式。

一种方法(我通常采用)是将每个Windows窗体分为三个实体:

  1. 演示者/控制器类-这是您在开发表单时实际开始的内容。这是您大多数/所有“业务”逻辑所在的位置。
  2. 视图界面(IView),其中包含方法,属性和事件。这个接口是所有演示者知道您的形式。
  3. 最后,当您完成演示者和视图的实现(包括单元测试)时,您可以创建实际的表单类并使其实现IView接口。然后,这只是将适当的控件添加到表单并将它们连接到界面的问题。

示例代码(一个简单的伪代码,仅用于说明):

interface IView
{
    string Username { get; set; }
    string Password { get; set; }

    event EventHandler LogOnButtonClicked;

    void InformUserLogOnFailed();
    void MoveToMainScreen();
}

class Presenter
{
    public Presenter(IView view)
    {
        this.view = view;
        view.LogOnButtonClicked += new EventHandler(OnLogOnButton);
    }

    private void OnLogOnButton()
    {
        // we ask some service to verify the username/password
        bool isLogOnOk = logOnService.IsUserAndPasswordOk(view.Username, view.Password);
        if (isLogOnOk)
            view.MoveToMainScreen();
        else
        {
            view.Username = "";
            view.Password = "";
            view.InformUserLogOnFailed();
        }
    }

    private IView view;
}

class Form : IView
{
    public Form()
    {
        presenter = new Presenter(this);
    }

    public string Username
    {
        get { return TextBoxUsername.Text; }
        set { TextBoxUsername.Text = value; }
    }

    public string Password
    {
        get { return TextBoxPassword.Text; }
        set { TextBoxPassword.Text = value; }
    }

    public void InformUserLogOnFailed()
    {
        MessageBox.Show("Invalid username or password.");
    }

    public void MoveToMainScreen()
    {
        // code for opening another form...
    }

    private Presenter presenter;
}

7
这是称为PassiveView的MVP变体的实现。在被动视图中,视图不应选择其主持人。对于类似的示例(但视图实际上是被动的),请检查此示例danieleteti.it/?p=221(以Delphi语言为示例)
Daniele Teti 2010年

6

您看过PureMVC吗?我发现,一旦他们开始构建特定的实现,没人会同意MVC的真正外观。

更新:您可以从诸如MobileMVC之类的简单对象开始构建自己的对象。Compact Framework代码应在Windows上编译/运行即可。由于这是学校的作业,因此我建议您实际上花一些时间来学习MVC的实际工作方式。


我有一个学校作业,负责一个非常简单的应用程序来管理书店,并且我不太愿意使用PureMVC之类的框架。我正在寻找更简单的东西。
kjv


2

这里可以找到一个很好的示例,说明使用Windows窗体滚动自己的MVC实现。包含源代码。

在阅读,研究和编写此作业的代码时,您会发现在如何实现MVC方面存在很多分歧。这是一个简单的案例,反映了关注点的分离,同时也是将其挂接起来所需的“管道”的一个很好的例子。

当您放学时,您可能想要回到其他海报推荐的框架上。


2

Microsoft复合接口应用程序块从MVC实现开始(在其实现的其他模式中)。但是,发行版演变为MVP实现,可以认为这是对MVC概念的一种不同解释。

如果您愿意检查一个非常完整(以及某种程度上复杂)的MVP实现的代码,则可以找到MS-CAB作为Microsoft Smart Client Software Factory的组件之一。它带有源代码。你可以在这里找到它。祝好运!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.