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

jMVC.NET:使用简洁的 MVC 编码轻松实现动态客户端 UI

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.26/5 (9投票s)

2007 年 11 月 28 日

CPOL

5分钟阅读

viewsIcon

40734

downloadIcon

292

jMVC.NET 是一个 ASP.NET 控件,可帮助您构建动态更改的 UI,而无需回发、AJAX 或复杂的事件处理。

引言

在 ASP.NET 中编程动态 UI 至少可以说是一件棘手的事情。如果您以编程方式添加和删除控件以响应用户输入,则必须费尽周折才能使 ViewState 和控件事件正常工作。事情很容易变得混乱,并且可能隐藏错误(是否曾见过“无法加载 Viewstate”错误?)。此外,由于所有这些回发,最终用户的体验可能很糟糕。AJAX 和 UpdatePanel 可以提供一些帮助,但从根本上说,这应该比这更容易——对吧?

是的。jMVC.NET 旨在简化此任务,从而为开发人员和最终用户提供更好的体验。您可以将 jMVC:MVCPanel 控件放入现有的 ASP.NET WebForm 页面中(与其他传统 ASP.NET Web 控件一起),MVCPanel 将根据您提供的模板托管动态控件结构。我们使用 Model-View-Controller 模式来保持事物整洁有序,在服务器端,您可以使用强类型 C#/VB.NET 对象来设置和检索用户正在编辑的数据。

在线演示托管在外部网站上,展示了“Hello world”、“Simple list editor”、“Client-side grid”和“Hierarchical folders editor”演示的源代码和交互式 UI。更多演示在我的博客上。

教程:任务列表

在我们的教程中,让我们假装我们在制作一个简单的任务管理器应用程序。用户希望管理一个任务列表,其中每个任务可能已完成或未完成,我们假设他们可以添加一些可选的备注。我们希望最终的 UI 看起来像这样

Screenshot - jmvcnet2.png

请记住,为了保持应用程序的响应性,任务列表的更改应该在无需回发或 AJAX 请求的情况下工作。

安装

首先,为 jMVC.NET DLL(以及同样提供的 json.net DLL)添加项目引用

接下来,在您将要添加控件的 ASPX 页面中,添加对 jMVC 的引用

添加控件

现在您可以在 ASPX 表单内的任何位置添加 jMVC:MVCPanel 控件。

(请注意,我们引用了一个尚不存在的名为 tasklist.jmvc 的文件——我们稍后会回来处理这个问题。)

添加模型

在您的代码隐藏中,将数据模型定义为一个 .NET 对象,并将其分配给 TaskListControl 控件。

    public partial class TaskList : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if(!IsPostBack)
                TaskListControl.Model["tasks"] = new List<Task>();
        }

        private class Task
        {
            public string Name;
            public bool IsCompleted;
            public bool HasNotes;
            public string Notes;
        }
    }

添加视图

到目前为止一切顺利!我们有了数据模型;接下来我们需要一个视图。在与您的 ASPX 页面相同的目录中创建一个空白文本文件,并将其命名为 tasklist.jmvc——这将是我们之前引用的模板。

您可以先在 tasklist.jmvc 模板中添加stringHello, world!”。然后运行您的应用程序,页面将在 TaskListControl 控件的位置显示 stringHello, world!”。

真实的视图

好的,“hello world”不够。事实证明,您的老板想要一个真正能做事的应用程序。编辑您的 tasklist.jmvc 文件,使其看起来像这样(如果您不确定它是如何工作的,请不要担心)

<% if(model.tasks.length == 0) { %>
    <p>No tasks have been added.</p>
<% } else { %>
    <table border="1" cellpadding="6">
        <thead>
            <tr>
                <th align="left">Task</th>
                <th align="left">Status</th>
                <th align="left"></th>
            </tr>
        </thead>
        <% for(var i = 0; i < model.tasks.length; i++) { %>
            <tr>
                <td>
                    <span style='<%= model.tasks[i].IsCompleted ?
                    "text-decoration:line-through" : "font-weight:bold" %>'>
                        <%= model.tasks[i].Name %>
                    </span>
                </td>
                <td>
                    <label>
                        <input type="checkbox" onclick="<%* function(i)
                    { model.tasks[i].IsCompleted = this.checked } %>"
                            <%= model.tasks[i].IsCompleted ? "checked" : "" %> />
                        Completed
                    </label>
                    <label>
                        <input type="checkbox" onclick="<%* function(i)
                    { model.tasks[i].HasNotes = this.checked } %>"
                            <%= model.tasks[i].HasNotes ? "checked" : "" %> />
                        Has notes
                    </label>
                    <% if(model.tasks[i].HasNotes) { %>
                        <div><textarea onchange="<%* function(i)
                    { model.tasks[i].Notes = this.value; } %>">
                            <%= model.tasks[i].Notes %></textarea></div>
                    <% } %>
                </td>
                <td>
                    <a href="#" onclick="<%* function(i)
                    { model.tasks.splice(i, 1); } %>"">Delete</a>
                </td>
            </li>
            </tr>
        <% } %>
    </table>
<% } %>

Add new task:
<input type="text" id="NewTaskName" onkeypress="return event.keyCode != 13;
            /* don't submit form if ENTER is pressed */"/>
<input type="button" value="Add" onclick="<%* function()
        { addNewTask(model.tasks); } %>" />

<%
    function addNewTask(taskList) {
        var taskName = document.getElementById("NewTaskName").value;
        if(taskName != "")
            taskList[taskList.length] = { Name : taskName, Notes : "" };
    }
%>

完成工作

完成!运行您的应用程序,您会发现页面现在完全交互。看,没有回发!最后的任务是在服务器端接收更新后的数据并对其进行处理(例如,将其保存到数据库)。

那都是关于什么的?

jMVC 语法一开始可能有点陌生,但实际上它是一种将数据模型映射到一组交互式 HTML 控件的非常简洁的方式。与传统面向服务器的 ASP.NET(无论是否使用 AJAX)实现相同的行为相比,这无疑需要的工作量要少得多,而代码量少意味着错误更少。

请注意,这部分的服务器端是多么简洁:代码几乎不到三行,并且我们在浏览器中使用强类型的 .NET 数据模型进行交互。

jMVC 模板语法仅由 HTML 组成,外加三个可以在浏览器中运行的控件结构

  • 评估 使用 <%= model.property %> 语法,并将评估结果插入生成的 UI 中。
  • 流程控制 使用 <% /* Javascript here */ %> 语法,通常用于在模型上进行迭代或递归,如下所示:

    <% for(var i = 0; i < model.items.length; i++) { %>
        Item: <%= model.items[i].name %>
    <% } %>
  • 闭包(花哨的)使用 <%* function() { /* Javascript here */ } %> 语法,并用于添加事件处理程序,如下所示:

    <input type="button" onclick="background-color: Yellow;"><%* function(i)
        { alert("This is item number " + i); } background-color: Yellow;">%>"/>

核心工作流程是,您的 .NET 数据模型会自动转换为 JSON,并且 jmvc 模板充当从 JSON 数据到一组 HTML 控件的映射。每当您的闭包之一编辑底层数据模型时,UI 都会自动重新生成以显示更改的效果。当您最终进行实际回发时,JSON 数据将被映射回 .NET 对象,供您的服务器端代码获取。

更多信息

技巧 1: 如果您希望 Visual Studio 为 jMVC 文件提供正确的语法高亮显示,请右键单击该文件,选择“打开方式...”,然后选择“HTML 编辑器”。

技巧 2: 交互式示例和源代码可在外部网站上找到。

技巧 3: 本文重点介绍了将 jMVC 控件与 ASP.NET 集成,但我的博客还提供了关于将 jMVC 用作独立 JavaScript 库与 Castle MonoRail 集成的文章。还有一个面向 ASP.NET 程序员的另一个 jMVC.NET 教程

技巧 4: 您可以通过启用调试信息来查看 jMVC.NET 的工作原理(即实时更新 JSON 数据模型),如下所示:

历史

  • 2007 年 11 月 25 日:首次撰写
© . All rights reserved.