65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP.NET Web Forms 应用程序中实现 MVC 模式。

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (30投票s)

2013年10月3日

CPOL

4分钟阅读

viewsIcon

66387

downloadIcon

2035

本教程描述了 MVC 模式,并说明了如何在 ASP.Net Web Forms 应用程序中实现 MVC 模式。

引言

本教程通过图示向技术人员和非技术人员描述了 MVC 模式。本教程还通过示例展示了如何在 ASP.NET Web Forms 应用程序中实现 MVC 模式。

目录

  • 第一部分: MVC 模式(Model-View-Controller)简介。
  • 第二部分: 使用 MVC 模式的 ASP.NET Web Forms 项目示例。

第一部分: MVC 模式简介

什么是设计模式?

根据我的理解,模式是在软件开发中针对重复出现问题的解决方案。模式是使用面向对象原则实现的。它是对特定问题的已批准解决方案。例如,观察者模式用于通知依赖于某个对象的对象,而这些对象又依赖于该对象。观察者模式在 MVC 实现中使用。

什么是 MVC?

模型-视图-控制器 (MVC) 是一种流行的 UI 设计模式。它用于表示表示层。该模式分离了应用程序代码。MVC 模式有三个组件,分别称为模型 (Model)、视图 (View) 和控制器 (Controller)。下图说明了 MVC 模式的组件及其关系,即使非技术读者也能清楚理解。

图: MVC 模式的组件及其关系(非技术图例)

上图清楚地展示了 MVC 的主要组件及其关系。让我们详细描述一下。

视图 (View): 视图表示用户界面。它显示的数据来自模型组件。当控制器更新模型时,视图会收到模型的更新通知。

  • 控制器 (Controller): 控制器充当视图和模型之间的中介。当用户触发事件时,视图会接收该事件并将其交给控制器。然后控制器进行数据验证,如果有效,则更新模型。它还会在需要时更新视图。
  • 模型 (Model): 模型包含应用程序的数据。当控制器更改模型数据时,模型会通知视图进行更新,然后视图从模型获取更新的数据并更新 UI。

下图是 MVC 模式的 UML 类图。

图: MVC 模式的组件及其关系(技术图例)。

上图展示了类及其之间的关系。在这里,控制器和视图类之间存在双向关系。模型和视图之间也存在双向关系,而控制器和模型之间是单向关系。

下图是 MVC 模式的序列图。

图: MVC 模式的序列图。

上面的序列图从用户请求开始,当用户在 UI 上触发事件时。视图向控制器发送 `RequestUpdate` 消息,并将自身作为参数传递。控制器向模型发送 `UpdateData` 消息,并将更新后的值作为参数传递。在模型本身更新后,它使用 `NotifyUpdate` 消息通知视图,并将自身作为参数传递。收到通知后,视图会使用更新后的值更新 UI,并从模型获取更新的值。

以上就是关于 MVC 模式及其组件模型以及它们如何通过方法调用进行交互的内容。

第二部分: 使用 MVC 模式的 ASP.NET Web Forms 项目示例

概述

以下屏幕截图提供了我将要解释的 ASP.NET Web Forms 应用程序的快速概览。当您从 Visual Studio 运行该应用程序时,将看到以下输出。

项目描述

该示例应用程序显示了 Windows 操作系统配置要求,用户可以更新这些配置。

现在,是时候逐步深入项目了。

  1. 创建一个 ASP.NET Web Forms 项目,如下图所示的解决方案资源管理器屏幕截图。

描述: 在新创建的项目中,我添加了三个名为 Controllers、Models 和 Views 的文件夹,分别用于存放控制器、模型和视图类。

2. 在文件 `Windows98Controller.cs` 中创建一个控制器类。以下代码显示了控制器类。

public class Window98Controller
{
    private Window98Model Model;
    private Windows98View View;
    public Window98Controller(Window98Model paramModel, Windows98View paramView)
    {
        Model = paramModel;
        View = paramView;
    }
    public void InitializedConponent(bool ispostback)
    {
        if(!ispostback)
            View.InitializedView(Model);
    }
    public Window98Controller()
    {
    }
    public void RequestUpdate(Windows98View view)
    {
        if (Model != null)
        {
           Model.UpdateModel(view.Ram,view.Disk,view.CPUSpeed);
        }
    }
}

描述: 构造函数 `Window98Controller (Window98Model paramModel, Windows98View paramView)` 用于将模型和视图传递给控制器,以便在编译时建立它们之间的关系并初始化值。`RequestUpdate()` 方法由视图调用,它会调用模型的 `UpdateModel()` 方法。

3. 在文件 `Windows98Model.cs` 中创建一个模型类。以下代码显示了模型类

public class Window98Model
{
    private ArrayList aList = new ArrayList();
    public Window98Model(string paramName,decimal paramMinRam,
        decimal paramMinDisk, decimal    paramCpuSpeedd)
    {
        MinRam = paramMinRam; 
        MinDisk = paramMinDisk;
        CPUSpeed = paramCpuSpeedd;
        Name = paramName;
        Ram = paramMinRam;
        Disk = paramMinDisk;
    }
    public string Name{ get; set;}
    public decimal Ram { get; set; }
    public decimal Disk { get; set; }
    public decimal MinRam { get; set; }
    public decimal MinDisk { get; set; }
    public decimal CPUSpeed { get; set; }
    public void UpdateModel(decimal paramRam, decimal paramDisk, decimal paramCPUSpace)
    {
        Ram += paramRam;
        Disk += paramDisk;
        CPUSpeed += paramCPUSpace;
        this.NotifyObservers();
    }
    public void AddObserver(Windows98View paramView)
    {
        aList.Add(paramView);
    }
    public void RemoveObserver(Windows98View paramView)
    {
        aList.Remove(paramView);
    }
    public void NotifyObservers()
    {
        foreach (Windows98View view in aList)
        {
            view.Update(this);
        }
    }
}

描述: 这里使用构造函数来初始化模型。`UpdateModel()` 方法用于更新模型,由控制器调用。`AddObserver()` 和 `RemoveObserver()` 方法分别用于将视图添加为模型的观察者和从模型中删除观察者。`NotifyObservers()` 方法用于遍历观察者列表并通知所有观察者。这里只使用了一个观察者。

4. 创建一个名为 `Windows98View.ascx` 的用户控件。

视图的 HTML 部分如下所示。

<%@ Control Language=C# AutoEventWireup=true CodeBehind=Windows98View.ascx.cs
 Inherits=MVCForWinForms.Views.Windows98View %>
<div style="height: 30px; background-color: rgb(0, 148, 255); color: white; margin-bottom: 10px;">
    <asp:label style="display: block;" 
      text="Windows 98 System Configuration" runat="server" id="label1" />
</div>
<span style="float: left; font-weight: bold; color: rgb(0, 148, 255);">Current Status:&nbsp;</span>
<span>Ram:</span><asp:label runat="server" id="lblRam" /><span>GB</span>
<span>Disk:</span><asp:label runat="server" id="lblDisk" /><span>GB</span>
<span>CPU Speed:</span><asp:label runat="server" id="lblcpuspeed" /><span>GHz</span>
<table style="padding: 10px 0px; float: left; width: 365px;">
    <tbody><tr>
        <td style="font-weight: bold;">RAM:</td>
        <td><asp:textbox runat="server" id="txtRam" /></td>
        <td>GB</td>
    </tr>
    <tr>
        <td style="font-weight: bold;">Disk Space:</td>
        <td><asp:textbox runat="server" id="txtDisk" /></td>
        <td>GB</td>
    </tr>
    <tr>
        <td style="font-weight: bold;">Processor:</td>
        <td><asp:textbox runat="server" id="txtProcessor" /></td>
        <td>GHz</td>
    </tr>
    <tr>
        <td>
            <asp:button onclick="btnUpdate_Click" 
              text="Update" runat="server" id="btnUpdate">
        </asp:button></td>
        <td></td>
        <td></td>
    </tr>
</tbody>
</table>

视图的代码隐藏部分如下所示。

public partial class Windows98View : System.Web.UI.UserControl
{
    private Window98Controller Control;
    private Window98Model Model = new Window98Model("Windows 98", 2, 10, 2);
    protected void Page_Load(object sender, EventArgs e)
    {
        Control = new Window98Controller(Model,this);
        Model.AddObserver(this);
        Control.InitializedConponent(IsPostBack);
    }
    public decimal Ram { get; set; }
    public decimal Disk { get; set; }
    public decimal CPUSpeed { get; set; }
    protected void btnUpdate_Click(object sender, EventArgs e)
    {
        CPUSpeed = Convert.ToDecimal(txtProcessor.Text.ToString());
        Ram = Convert.ToDecimal(txtRam.Text.ToString());
        Disk = Convert.ToDecimal(txtDisk.Text.ToString());
        Control.RequestUpdate(this);
    }
    public void Update(Window98Model paramModel)
    {
        UpdateInterface(paramModel);
    }
    public void UpdateInterface(Window98Model auto)
    {
        if (Ram != auto.Ram)
        {
            lblRam.Text = auto.Ram.ToString("n2");
        }
        if (Disk != auto.Disk)
        {
            lblDisk.Text = auto.Disk.ToString("n2");
        }
        if (CPUSpeed != auto.CPUSpeed)
        {
            lblcpuspeed.Text = auto.CPUSpeed.ToString("n2");           
        }
    }
    public void InitializedView(Window98Model paramModel)
    {
        lblRam.Text = paramModel.Ram.ToString("n2");
        lblDisk.Text = paramModel.Disk.ToString("n2");
        lblcpuspeed.Text = paramModel.CPUSpeed.ToString("n2");
    }
}

描述: 这里创建了一个具有初始值的模型对象,并将其传递给其控制器类,然后调用其 `AddObserver()` 方法将视图绑定为观察者。

注意: 这里没有使用关系数据库。模型通过将其数据传递到其构造函数来初始化,而视图则使用该数据进行初始化。

5. 最后,创建一个页面 `SystemCheck.aspx`,在该页面上运行用户控件。页面的 HTML 部分如下所示。

<%@ Page Language="C#" AutoEventWireup="true" 
     CodeBehind="SystemCheck.aspx.cs" Inherits="MVCForWinForms.SystemCheck" %>
<%@ Register Src="~/Views/Windows98View.ascx" TagPrefix="uc3" TagName="Windows98" %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
        body {
            font-family:Verdana;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <div style="border:1px solid; width:500px; height:500px; margin:auto auto;">
        <uc3:Windows98 runat="server" id="Windows98" />
    </div>
    </form>
</body>
</html>

结论

此示例包含了视图、模型和控制器之间的耦合。为了重用模型和进行单元测试,我们应该减少耦合和对视图的依赖。在接下来的教程中,我将描述如何减少耦合并为其他操作系统配置重用模型,以及如何进行单元测试。

© . All rights reserved.