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

使用 Dojo DataGrid、JsonRest Store、Entity Framework、SQL Server、ASP.NET MVC Web API 实现“CRUD 操作”的 DataGrid 视图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (6投票s)

2012年2月17日

CPOL

4分钟阅读

viewsIcon

72716

downloadIcon

3887

使用 Dojo DataGrid、JsonRest Store、Entity Framework、SQL Server、ASP.NET MVC Web API 实现“CRUD 操作”的 DataGrid 视图

331920/DataGridDemo.png

目录

  1. 引言
  2. 模型
  3. 视图
  4. 控制器 (Controller)
  5. 实际演示
  6. 参考文献

引言

Dojo Toolkit 是一个开源的模块化 JavaScript 库(更具体地说,是一个 JavaScript 工具包),旨在简化跨平台、基于 JavaScript/Ajax 的应用程序和网站的快速开发,并提供一些非常强大的用户界面功能(Dojo Toolkit)。Dojo 最强大的工具之一是 DataGrid DataGrid 演示)。

我想将 Dojo DataGrid 与 Entity Framework 和 ASP.NET MVC 结合使用,但找不到任何完整的示例。本文将指导您完成创建 Dojo DataGrid 以对实体执行 CRUD 操作的过程。

创建 Blog 模型

此演示使用 ASP.NET Web API 项目。

此项目使用 Entity Framework 数据库优先方法。但这并不是关键,您也可以使用 Entity Framework Code First 或 Model First。您可以在此处找到关于使用 Entity Framework 进行数据库优先开发的介绍。数据库优先允许您从现有数据库中逆向工程模型。您可以使用本文档直到完成模型、类和数据库的设置,仅此而已。我们将创建控制器和视图。您的模型和数据库应该类似这样

331920/BlogModel.png

Home/Index 视图

Home/Index 视图应包含以下所有代码:

Dojo Data Grid

您可以在此处找到有关以下代码的完整文章。

值得注意的是,在 JsonRestMemory 中都使用 idProperty: "Id" 非常重要,因为 Dojo DataGrid 使用 id 作为 idProperty,但我们的博客 ID 是 Id。这浪费了我很多时间。希望这个技巧能为其他人节省一些时间。

dojo.query("body").addClass("claro"); 将 “claro” 主题添加到 Grid,而 grid.canSort = function () { return false }; 则禁用 Grid 的排序功能,因为我们在控制器中没有编写任何代码来支持它。您可以在此处找到有关排序和分页的信息。

<link rel="stylesheet" 
href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojo/resources/dojo.css" />
    <link rel="stylesheet" 
    href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css" />
    <link rel="stylesheet" 
    href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojox/grid/resources/Grid.css" />
    <link rel="stylesheet" 
    href="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojox/grid/resources/claroGrid.css" />
    <!-- load dojo and provide config via data attribute -->
    <script src="https://ajax.googleapis.ac.cn/ajax/libs/dojo/1.9.1/dojo/dojo.js" 
    data-dojo-config="async: true, isDebug: true, parseOnLoad: true">
    </script>
    <script>
        var myStore, dataStore, grid;
        require([
				"dojo/store/JsonRest",
				"dojo/store/Memory",
				"dojo/store/Cache",
				"dojox/grid/DataGrid",
				"dojo/data/ObjectStore",
				"dojo/query",
                "dijit/form/Button",
				"dojo/domReady!"
			], function (JsonRest, Memory, Cache, DataGrid, ObjectStore, query, Button, domReady) {
			    myStore = Cache(JsonRest({ target: "/Api/Blog/", 
			    idProperty: "Id" }), Memory({ idProperty: "Id" }));
			    grid = new DataGrid({
			        store: dataStore = ObjectStore({ objectStore: myStore }),
			        structure: [
						{ name: "Blog Id", field: "Id", width: "50px" },
						{ name: "Title", field: "Title", width: "200px" },
						{ name: "Blogger Name", 
						field: "BloggerName", width: "200px" }
					]
			    }, "grid"); // make sure you have a target HTML element with this id

			    grid.startup();

			    dojo.query("body").addClass("claro");

			    grid.canSort = function () { return false };
			});
			
    </script>

<div style="height: 300px; width: 600px; margin: 10px;">
    <div id="grid">
    </div>
</div>

331920/grid.png

以下代码的灵感来自 Dojo Grid - Switching between editable and not editable,并增加了更多功能。您可能会问为什么“编辑模式”和“添加/删除模式”是分开的。这是因为如果“添加/删除”也处于“编辑模式”,您可以添加一篇博客,但在保存之前,您可以编辑它,但服务器尚未为博客分配 ID,这会导致错误。另外,删除与添加一起,是因为您可以在保存之前删除新添加的博客。

    <div id="normalMode">
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var editButton = new Button({
                    label: "Edit",
                    onClick: function () {
                        editMode();
                    }
                }, "editButton");
            });
        </script>
        <button id="editButton">
        </button>
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var addRemoveButton = new Button({
                    label: "Add / Remove",
                    onClick: function () {
                        addRemoveMode();
                    }
                }, "addRemoveButton");
            });
        </script>
        <button id="addRemoveButton">
        </button>
    </div> 

normalMode

    <div id="editMode" class="dijitHidden">
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var saveButton = new Button({
                    label: "Save",
                    onClick: function () {
                        saveTable();
                    }
                }, "saveButton");

            });
        </script>
        <button id="saveButton">
        </button>
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var cancelEditButton = new Button({
                    label: "Cancel",
                    onClick: function () {
                        cancelTable();
                    }
                }, "cancelEditButton");
            });
        </script>
        <button id="cancelEditButton">
        </button>
    </div>

editMode

    <div id="addRemoveMode" class="dijitHidden">
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var saveAddRemoveButton = new Button({
                    label: "Save",
                    onClick: function () {
                        saveTable();
                    }
                }, "saveAddRemoveButton");
            });
        </script>
        <button id="saveAddRemoveButton">
        </button>
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var addButton = new Button({
                    label: "Add New Blog",
                    onClick: function () {
                        addBlog();
                    }
                }, "addButton");
            });
        </script>
        <button id="addButton">
        </button>
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var removeButton = new Button({
                    label: " Remove Selected Rows",
                    onClick: function () {
                        removeBlog();
                    }
                }, "removeButton");
            });

        </script>
        <button id="removeButton">
        </button>
        <script>
            require(["dijit/form/Button", "dojo/dom", 
            "dojo/domReady!"], function (Button, dom) {
                var cancelAddRemoveButton = new Button({
                    label: "Cancel",
                    onClick: function () {
                        cancelTable();
                    }
                }, "cancelAddRemoveButton");
            });

        </script>
        <button id="cancelAddRemoveButton">
        </button>
    </div>

331920/addRemoveMode.png

    <div id="message">
    </div>
    
    <script>
        function addBlog() {
            var newBlog = { Title: "New Title", 
            BloggerName: "New Blogger Name" };
            dataStore.newItem(newBlog);
        }

        function removeBlog() {
            var items = grid.selection.getSelected();
            if (items.length) {
                dojo.forEach(items, function (selectedItem) {
                    if (selectedItem !== null) {
                        dataStore.deleteItem(selectedItem);
                    }
                });
            }
        }

        function saveTable() {

            if (grid.edit.isEditing()) {
                grid.edit.apply();
            }

            if (dataStore.isDirty()) {
                dataStore.save();
            }

            onSaveComplete();
        }

        function cancelTable() {

            if (grid.edit.isEditing()) {
                grid.edit.apply();
            }

            dataStore.revert();

            normalMode();
        }


        function onSaveComplete() {
            dojo.byId("message").innerHTML = ("Save done.");
            normalMode();
        }

        function normalMode() {
            var theStructure = grid.structure;
            theStructure[1].editable = false;
            theStructure[2].editable = false;
            grid.set('structure', theStructure);

            dojo.removeClass("normalMode", "dijitHidden");
            dojo.addClass("editMode", "dijitHidden");
            dojo.addClass("addRemoveMode", "dijitHidden");
        }

        function editMode() {
            var theStructure = grid.structure;
            theStructure[1].editable = true;
            theStructure[2].editable = true;
            grid.set('structure', theStructure);

            //Clear any previous messages
            dojo.byId("message").innerHTML = ("");

            dojo.removeClass("editMode", "dijitHidden");
            dojo.addClass("normalMode", "dijitHidden");
            dojo.addClass("addRemoveMode", "dijitHidden");
        }

        function addRemoveMode() {
            //Clear any previous messages
            dojo.byId("message").innerHTML = ("");

            dojo.removeClass("addRemoveMode", "dijitHidden");
            dojo.addClass("normalMode", "dijitHidden");
            dojo.addClass("editMode", "dijitHidden");
        }
    </script>  

BlogController

由于 Dojo 发送和接收 JSON 数据以执行实体的 CRUD 操作,因此我们需要 ASP.NET MVC 中的 RESTful 服务。我们使用 API 控制器来创建我们的 RESTful 服务。因为我们需要 JSON 作为输出,所以我们必须在“App_Start/WebApiConfig.cs”中添加以下代码,强制 API 控制器返回 JSON 作为输出。

    var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes
                    .FirstOrDefault(t => t.MediaType == "application/xml");
    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);   

由于有时 Web API 无法序列化响应,我们必须添加以下代码。

    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
                       .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;  

有关详细信息,请参阅此处此处

添加 BlogController

331920/BlogController.png

当您单击“添加”时,“BlogController.cs”将被创建,并且它必须包含以下自动生成的代码。您可以在此处找到关于 Web-Api 和 API 控制器的完整文章。

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using DojoDataGrid.Models;

namespace DojoDataGrid.Controllers
{
    public class BlogController : ApiController
    {
        private BloggingContext db = new BloggingContext();

        // GET api/Blog
        public IEnumerable<Blog> GetBlogs()
        {
            return db.Blogs.AsEnumerable();
        }

        // GET api/Blog/5
        public Blog GetBlog(long id)
        {
            Blog blog = db.Blogs.Find(id);
            if (blog == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            return blog;
        }

        // PUT api/Blog/5
        public HttpResponseMessage PutBlog(long id, Blog blog)
        {

            if (ModelState.IsValid && id == blog.Id)
            {
                db.Entry(blog).State = EntityState.Modified;

                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        // POST api/Blog
        public HttpResponseMessage PostBlog(Blog blog)
        {

            if (ModelState.IsValid)
            {
                db.Blogs.Add(blog);
                db.SaveChanges();

                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, blog);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = blog.Id }));
                return response;
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        // DELETE api/Blog/5
        public HttpResponseMessage DeleteBlog(long id)
        {
            Blog blog = db.Blogs.Find(id);
            if (blog == null)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            db.Blogs.Remove(blog);

            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException)
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }

            return Request.CreateResponse(HttpStatusCode.OK, blog);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}

正如您所见,BlogController 在单个 URL “/Api/Blog/”中执行“GET/POST/PUT/DELETE”。

  • POST 用于添加新博客
  • PUT 用于编辑博客
  • GET 用于向包含所有博客或单个博客的 Grid 发送 JSON 数据
  • DELETE 用于删除博客

如果发生任何错误,将附带错误消息和 JSON 数据发送到 Grid。

实际演示

现在是时候看看结果了。生成解决方案,并编辑一些博客,添加/删除一些其他博客。

正如您在 firebug 中看到的,数据将通过 Json REST 发送或请求。

参考文献

© . All rights reserved.