在ASP.NET MVC4中實現同頁面增刪改查,無彈出框02,增刪改查界面設計


在上一篇"在ASP.NET MVC4中實現同頁面增刪改查,無彈出框01,Repository的搭建"中,已經搭建好了Repository層,本篇就剩下增刪改查的界面了......今天的陽光真特么好,寫完本篇,好出去在陽光下溜溜狗、散散步什么的,正所謂文武之道一張一弛,走神了,進入正題。

 

首先是一個View Model,在這里定義驗證規則,提交和保存數據的時候還必須和領域模型映射。

using System;
using System.ComponentModel.DataAnnotations;
namespace MvcApplication3.Models
{
    public class ProductVm
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "必填")]
        [Display(Name = "名稱")]
        [StringLength(6,  ErrorMessage = "最大長度6位")]
        public string Name { get; set; }
        [Required(ErrorMessage = "必填")]
        [Display(Name = "分類")]
        [StringLength(6, ErrorMessage = "最大長度6位")]
        public string Category { get; set; }
        [Required(ErrorMessage = "必填")]
        [Display(Name = "價格")]
        [Range(typeof(Decimal), "0", "9999", ErrorMessage = "{0} 必須是數字介於 {1} 和 {2}之間.")]
        public decimal Price { get; set; }   
    }
}

 

創建HomeController

 

using System.Linq;
using System.Web.Mvc;
using MvcApplication3.Models;
namespace MvcApplication3.Controllers
{
    public class ProductController : Controller
    {
        static readonly IProductRepository repository = new ProductRepository();
        #region 顯示查詢
        /// <summary>
        /// 顯示主界面
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View();
        }
        private string _name = string.Empty; //用來接收查詢中有關Name的值
        private string _category = string.Empty;//用來接收查詢中有關Category的值
        /// <summary>
        /// 根據查詢參數獲取所有產品,以json返回
        /// </summary>
        /// <returns></returns>
        public ActionResult GetProdutJson()
        {
            //page和rows是datagrid傳遞的默認參數
            int pageIndex = int.Parse(Request["page"]);
            int pageSize = int.Parse(Request["rows"]);
            //如果查詢中包括Name
            if (!string.IsNullOrEmpty(Request["name"]))
            {
                _name = Request["name"];
            }
            //如果查詢中包括Category
            if (!string.IsNullOrEmpty(Request["category"]))
            {
                _category = Request["category"];
            }
            //初始化查詢實例
            var queryParams = new ProductParam
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                Name = _name,
                Category = _category
            };
            //根據查詢實例查找對應的數據
            int totalNum = 0;
            var products = repository.LoadProductPageData(queryParams, out totalNum);
            //投影出需要傳遞給datagrid的數據
            var result = from p in products
                select new {p.Id, p.Name, p.Category, p.Price};
            //datagrid所需要的格式{total:10, rows=[]}
            var jsonResult = new {total = totalNum, rows = result};
            return Json(jsonResult, JsonRequestBehavior.AllowGet);
        }
        #endregion
        #region 添加
        /// <summary>
        /// 添加顯示,返回一個強類型部分視圖
        /// </summary>
        /// <returns></returns>
        public ActionResult AddProduct()
        {
            return PartialView("_AddProduct", new ProductVm());
        }
        /// <summary>
        /// 添加提交
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult AddProduct(ProductVm productVm)
        {
            if (ModelState.IsValid)
            {
                Product dbProduct = new Product();
                dbProduct.Name = productVm.Name;
                dbProduct.Category = productVm.Category;
                dbProduct.Price = productVm.Price;
                repository.Add(dbProduct);
                return Json(new { msg = true });
            }
            else
            {
                return PartialView("_AddProduct", new ProductVm());
            }
        }
        #endregion
        #region 修改
        /// <summary>
        /// 修改顯示
        /// </summary>
        /// <returns></returns>
        public ActionResult EditProduct(int id)
        {
            var dbProduct = repository.GetById(id);
            ProductVm productVm = new ProductVm();
            productVm.Id = dbProduct.Id;
            productVm.Name = dbProduct.Name;
            productVm.Category = dbProduct.Category;
            productVm.Price = dbProduct.Price;
            return PartialView("_EditProduct", productVm);
        }
        /// <summary>
        /// 修改提交
        /// </summary>
        /// <param name="productVm"></param>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult EditProduct(ProductVm productVm)
        {
            if (ModelState.IsValid)
            {
                var dbProduct = repository.GetById(productVm.Id);
                dbProduct.Name = productVm.Name;
                dbProduct.Category = productVm.Category;
                dbProduct.Price = productVm.Price;
                repository.Update(dbProduct);
                return Json(new { msg = true });
            }
            else
            {
                return PartialView("_EditProduct", productVm);
            }
        }
        #endregion
        #region 刪除
        /// <summary>
        /// 刪除
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public ActionResult DeleteProducts()
        {
            //獲取前台傳來的Id字符串
            var strIds = Request["ids"];
            //去除最后一位分隔符
            strIds = strIds.Substring(0, strIds.Length - 1);
            //把字符串轉換成數組
            string[] ids = strIds.Split('_');
            repository.DeleteBatch(ids);
            return Json(new { msg = true });
        }
        #endregion
    }
}

 

在前台頁面會使用jQuery EasyUI的datagrid顯示數據和分頁,而datagrid在向服務端發送異步請求的時候默認帶了pagerows這2個參數。GetProdutJson方法用來獲取查詢、分頁后的json格式。在前台,當頁面初次加載的時候,不帶任何查詢數據,服務端只要接收pagerows這2個參數,把它們封裝成一個類。

namespace MvcApplication3.Models
{
    public class PageParam
    {
        public int PageSize { get; set; }
        public int PageIndex { get; set; }  
    }
}

 

而當在前台輸入搜索條件的時候,搜索條件參數以及pagerows這2個參數都傳值給了服務端,為此我們再封裝一個派生於PageParam的類。

namespace MvcApplication3.Models
{
    public class ProductParam : PageParam
    {
        public string Name { get; set; }
        public string Category { get; set; }
    }
}


所以,在GetProdutJson方法內,最終是把從前台接收到的分頁參數或查詢參數,實例化成ProductParam的一個實例,再把該實例作為實參傳值給Repository的LoadProductPageData方法。

 

主界面Home/Index.cshtml

 

進入主界面Home/Index.cshtml之前,先設置_Layout.cshtml。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    <link href="~/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="~/Content/themes/icon.css" rel="stylesheet" />
    <link href="~/Content/themes/gray/easyui.css" rel="stylesheet" />
    @RenderSection("styles", required:false)
    @Scripts.Render("~/bundles/modernizr")
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/jqueryui")
    @Scripts.Render("~/bundles/jqueryval") 
    <script src="~/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
    @RenderBody()
   
    @RenderSection("scripts", required: false)
</body>
</html>

用到了bootstrap, jQuery EasyUI, jQuery等相關的css,js文件,該有的要有,順序要放對。

 

Product/Index.cshtml需要呈現的包括:

○ 添加區域:放在一個div中,div中再放一個iframe,需要的時候通過iframe鏈接到添加頁面
○ 修改區域:放在一個div中,div中再放一個iframe,需要的時候通過iframe鏈接到修改頁面
○ 搜索區域:使用bootstrap顯示元素
○ 列表區域:使用datagrid顯示,支持分頁

 

Product/Index.cshtml需要承擔的工作包括:

○ 頁面加載的時候隱藏添加和修改區域
○ 限制搜索區域有關名稱和類別的長度
○ 頁面加載顯示全部數據列表
○ 點擊搜索按鈕顯示符合搜素條件的數據列表
○ 點擊清空按鈕讓搜索條件清空
○ datagrid添加:讓添加區域內的iframe指向ProductController的
AddProduct方法,渲染強類型添加視圖
○ datagrid修改:讓修改區域內的iframe指向ProductController的
EditProduct方法,渲染強類型修改視圖,並傳遞當前Product的Id
○ datagrid刪除:支持批量刪除,把勾選行所在的Id拼接成"1_2_"的形式傳遞給PrductContrlller的
DeleteProduct方法,返回json
○ 提供給子視圖頁面調用的添加成功、添加取消、修改成功、修改取消方法,Home/Index.cshtml為父頁面,添加和修改區域內的iframe指向的視圖頁面是子頁面

 

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<!--添加開始-->
<div class="addContent" id="addContent">
    <iframe id="frameAdd" src="" scrolling="yes" frameborder="0" height="100%" width="100%" onload="this.height=this.contentWindow.document.documentElement.scrollHeight"></iframe>
</div>
<!--添加結束-->
<!--編輯開始-->
<div class="editContent" id="editContent">
    <iframe id="frameEdit" src="" scrolling="yes" frameborder="0" height="100%" width="100%" onload="this.height=this.contentWindow.document.documentElement.scrollHeight"></iframe>
</div>
<!--編輯結束-->
<!--搜索開始-->
<div id="tb" style="padding: 3px">
    <form class="form-inline" role="form">
        <div class="form-group">
            <label class="sr-only" for="name">名稱</label>
            <input type="text" class="form-control" name="name" id="name" placeholder="輸入名稱" maxlength="6" />
        </div>
        <div class="form-group">
            <label class="sr-only" for="category">分類</label>
            <input type="text" class="form-control" name="category" id="category" placeholder="輸入分類" maxlength="6"  />
        </div>
        <input type="button" id="btnSearch" class="btn btn-primary" value="搜索" />&nbsp;
        <input type="button" id="emptySearch" class="btn btn-default" value="清空" />
    </form>
</div>
<!--搜索結束—>
    
<!--表格開始-->
<div class="ctable" id="ctable">
    <table id="tt"></table>
</div>
<!--表格結束-->
@section scripts
{
    <script src="~/Scripts/jquery.easyui.min.js"></script>
    <script src="~/Scripts/easyui-lang-zh_CN.js"></script>
    <script type="text/javascript">
        $(function() {
            //隱藏元素
            initialHide();
            //限制搜索條件中名稱和分類的長度
            limitInputLength($('#name'));
            limitInputLength($('#category'));
            //顯示列表
            initData();
            //搜索
            $('#tb').on("click", "#btnSearch", function () {
                initData(initQuery());
            });
            //清空搜索
            $('#emptySearch').on("click", function () {
                emptySearch();
            });
        });
        //顯示列表
        function initData(params) {
            $('#tt').datagrid({
                url: '@Url.Action("GetProdutJson", "Product")',
                height: 360,
                width: 900,
                fitColumns: false,
                nowrap: true,
                showFooter: true,
                idField: 'ID',
                loadMsg: '正在加載信息...',
                pagination: true,
                singleSelect: false,
                queryParams: params,
                pageSize: 10,
                pageNumber: 1,
                pageList: [10, 20, 30],
                columns: [//p.Id, p.Name, p.Category, p.Price
                    [
                        { field: 'ck', checkbox: true, align: 'center', width: 30 },
                        { field: 'Id', title: '編號', align: 'center' },
                        { field: 'Name', title: '名稱', align: 'center' },
                        { field: 'Price', title: '價格', align: 'center' },
                        { field: 'Category', title: '分類', align: 'center' }
                    ]
                ],
                toolbar: [
                    {
                        id: 'btnAdd',
                        text: '添加',
                        iconCls: 'icon-add',
                        handler: function () {
                            showAdd();
                        }
                    }, '-', {
                        id: 'btnUpdate',
                        text: '修改',
                        iconCls: 'icon-edit',
                        handler: function () {
                            var rows = $('#tt').datagrid("getSelections");
                            if (rows.length != 1) {
                                $.messager.alert("提示", "只能選擇一行進行編輯");
                                return;
                            }
                            showEdit(rows[0].Id);
                        }
                    }, '-', {
                        id: 'btnDelete',
                        text: '刪除',
                        iconCls: 'icon-remove',
                        handler: function () {
                            var rows = $('#tt').datagrid("getSelections");
                            if (rows.length < 1) {
                                $.messager.alert("提示", "請選一行刪除");
                                return;
                            }
                            $.messager.confirm("提示信息", "確定要刪除嗎?", function (r) {
                                if (r) {
                                    var strIds = "";
                                    for (var i = 0; i < rows.length; i++) {
                                        strIds += rows[i].Id + '_'; //1_2_3
                                    }
                                    $.post("@Url.Action("DeleteProducts", "Product")", { ids: strIds }, function (data) {
                                        if (data.msg) {
                                            $.messager.alert("提示", "刪除成功");
                                            initData();
                                            $('#tt').datagrid("clearSelections");
                                        }
                                    });
                                }
                            });
                        }
                    }
                ],
                OnBeforeLoad: function (param) {
                    return true;
                }
            });
            }
            //添加
            function showAdd() {
                $("#frameAdd").attr("src", "@Url.Action("AddProduct", "Product")");
                $("#addContent").css("display", "block");
            }
            //修改
            function showEdit(productId) {
                var url = "/Product/EditProduct?id=" + productId;
                $("#frameEdit").attr("src", url);
                $('.addContent').css("display", "none");
                $("#editContent").css("display", "block");
            }
        //隱藏元素
        function initialHide() {
            $('.addContent').css("display", "none");
            $('.editContent').css("display", "none");
        }
        //限制文本框長度
        function limitInputLength(_input) {
            var _max = _input.attr('maxlength');
            _input.bind('keyup change', function () {
                if ($(this).val().length > _max) {
                    ($(this).val($(this).val().substring(0, _max)));
                }
            });
        }
        //子窗口添加成功后調用
        function refreshAfterAdd() {
            initData();
            $('#tt').datagrid("clearSelections");
            $("#addContent").css("display", "none");
        }
        //子窗口取消添加調用
        function cancelAdd() {
            $('.addContent').css("display", "none");
            $('#tt').datagrid("clearSelections");
        }
        //子窗口修改成功后調用
        function refreshAfterEdit() {
            initData();
            $('#tt').datagrid("clearSelections");
            $("#editContent").css("display", "none");
        }
        //子窗口取消修改調用
        function candelEdit() {
            $("#editContent").css("display", "none");
            $('#tt').datagrid("clearSelections");
        }
        //獲取查詢表單的值組成json
        function initQuery() {
            var queryParams = {
                name: $('#name').val(),
                category: $('#category').val()
            };
            return queryParams;
        }
        //清空搜索條件
        function emptySearch() {
            $('#name').val("");
            $('#category').val("");
        }
    </script>
}

 

 

添加強類型視圖頁Product/_AddProduct.cshtml

 

是一個針對ProductVm強類型視圖。添加成功或取消都會調用父視圖提供的方法。

@model MvcApplication3.Models.ProductVm
@{
    ViewBag.Title = "_AddProduct";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@section styles
{
    <style type="text/css">
        .errormsg {
            color: red;
        }
         .vcenter {
            display: table-cell;
            vertical-align: middle;
            float: none;
            border: 0px solid red;
            height: 38px;
        }
         .bk {
            background-color: #F8F8F8;
            padding: 2px;
            border-radius: 5px;
        }
         form {
             width: 900px;
             /*height: 450px;*/
         }
         .control-label {
             position: relative;
             top: 5px;
         }  
         .col-sm-6 {
             height: 40px;
         }
         .col-sm-2 {
             height: 40px;
         }
         .col-sm-4 {
             height: 40px;
         }
         #wrapper {
             width: 550px;
             clear: both;
             float: left;
             margin-top: 10px;
         }
    </style>
}
<div id="wrapper">
        @using (Html.BeginForm("AddProduct", "Product", FormMethod.Post, new { id = "addForm", @class = "form-horizontal", role = "form" }))
        {
            @Html.AntiForgeryToken()
            
            <div class="form-group">
                 @Html.LabelFor(s => s.Name,new { @class="col-sm-2 control-label" })
                <div class="col-sm-6">
                    @Html.TextBoxFor(s => s.Name,new { @class="form-control input-sm"})&nbsp;
                </div>
                <div class="col-sm-4 vcenter">
                    @Html.ValidationMessageFor(s => s.Name)
                </div>
            </div>    
            
            <div class="form-group bk">
                @Html.LabelFor(s => s.Price,new { @class="col-sm-2 control-label" })
                <div class="col-sm-6">
                    @Html.TextBoxFor(s => s.Price,new { @class="form-control input-sm"})&nbsp;
                </div>
                <div class="col-sm-4 vcenter">
                    @Html.ValidationMessageFor(s => s.Price)
                </div>
            </div>   
            
            <div class="form-group">
                @Html.LabelFor(s => s.Category,new { @class="col-sm-2 control-label" })
                <div class="col-sm-6">
                    @Html.TextBoxFor(s => s.Category,new { @class="form-control input-sm"}) &nbsp; 
                </div>
                <div class="col-sm-4 vcenter">
                    @Html.ValidationMessageFor(s => s.Category)
                </div>
            </div>     
                     
            <div class="form-group bk">
                <div style="text-align: center;" class="col-sm-6 col-sm-offset-2">
                    <input type="button" id="up" class="btn btn-primary" value="添加"/>
                    &nbsp;&nbsp;
                    <input type="button" id="cancel" class="btn btn-default" value="取消"/>
                </div>
            </div>                                   
        }
</div>
@section scripts
{
    <script type="text/javascript">
        $(function() {
            //提交
            $('#up').on('click', function () {
                if ($('#addForm').valid()) {
                    $.ajax({
                        cache: false,
                        url: '@Url.Action("AddProduct","Product")',
                        type: 'POST',
                        dataType: 'json',
                        data: $('#addForm').serialize(),
                        success: function (data) {
                            if (data.msg) {
                                $('input[type=text]').val("");
                                self.parent.refreshAfterAdd();
                                
                            }
                        },
                        error: function (xhr, status) {
                            alert("添加失敗,狀態碼:" + status);
                        }
                    });
                }
            });
            //點擊取消按鈕關閉窗口
            $('#cancel').on('click', function () {
                $('input[type=text]').val("");
                self.parent.cancelAdd();
            });
        });
    </script>
}

 

如果添加驗證失敗,客戶端適時報錯:
18

 

添加驗證成功,添加區域隱藏,列表多了新添加的數據:
19

 

修改強類型視圖頁Product/_EditProduct.cshtml

 

是一個針對ProductVm強類型視圖。修改成功或取消都會調用父視圖提供的方法。

@model MvcApplication3.Models.ProductVm
@{
    ViewBag.Title = "_EditProduct";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@section styles
{
    <style type="text/css">
        .errormsg {
            color: red;
        }
         .vcenter {
            display: table-cell;
            vertical-align: middle;
            float: none;
            border: 0px solid red;
            height: 38px;
        }
         .bk {
            background-color: #F8F8F8;
            padding: 2px;
            border-radius: 5px;
        }
         form {
             width: 900px;
             /*height: 450px;*/
         }
         .control-label {
             position: relative;
             top: 5px;
         }  
         .col-sm-6 {
             height: 40px;
         }
         .col-sm-2 {
             height: 40px;
         }
         .col-sm-4 {
             height: 40px;
         }
         #wrapper {
             width: 550px;
             clear: both;
             float: left;
             margin-top: 10px;
         }
    </style>
}
<div id="wrapper">
    @using (Html.BeginForm("EditProduct", "Product", FormMethod.Post, new { id = "editForm", @class = "form-horizontal", role = "form" }))
    {
        @Html.AntiForgeryToken()
        @Html.HiddenFor(s => s.Id)
        <div class="form-group">
            @Html.LabelFor(s => s.Name,new { @class="col-sm-2 control-label" })
            <div class="col-sm-6">
                @Html.TextBoxFor(s => s.Name,new { @class="form-control input-sm"})&nbsp;
            </div>
            <div class="col-sm-4 vcenter">
                @Html.ValidationMessageFor(s => s.Name)
            </div>
        </div>    
            
        <div class="form-group bk">
            @Html.LabelFor(s => s.Price,new { @class="col-sm-2 control-label" })
            <div class="col-sm-6">
                @Html.TextBoxFor(s => s.Price,new { @class="form-control input-sm"})&nbsp;
            </div>
            <div class="col-sm-4 vcenter">
                @Html.ValidationMessageFor(s => s.Price)
            </div>
        </div>   
            
        <div class="form-group">
            @Html.LabelFor(s => s.Category,new { @class="col-sm-2 control-label" })
            <div class="col-sm-6">
                @Html.TextBoxFor(s => s.Category,new { @class="form-control input-sm"}) &nbsp; 
            </div>
            <div class="col-sm-4 vcenter">
                @Html.ValidationMessageFor(s => s.Category)
            </div>
        </div>     
                          
            
        <div class="form-group bk">
            <div style="text-align: center;" class="col-sm-6 col-sm-offset-2">
                <input type="button" id="up" class="btn btn-primary" value="修改"/>
                &nbsp;&nbsp;
                <input type="button" id="cancel" class="btn btn-default" value="取消"/>
            </div>
        </div>                                   
    }
</div>
@section scripts
{
    <script type="text/javascript">
        $(function() {
            //提交
            $('#up').on('click', function () {
                if ($('#editForm').valid()) {
                    $.ajax({
                        cache: false,
                        url: '@Url.Action("EditProduct","Product")',
                        type: 'POST',
                        dataType: 'json',
                        data: $('#editForm').serialize(),
                        success: function (data) {
                            if (data.msg) {
                                self.parent.refreshAfterEdit();
                            }
                        },
                        error: function (xhr, status) {
                            alert("修改失敗,狀態碼:" + status);
                        }
                    });
                }
            });
            //點擊取消按鈕關閉窗口
            $('#cancel').on('click', function () {
                self.parent.candelEdit();
            });
        });
    </script>
}

如果修改驗證失敗,客戶端適時報錯:
20

 

修改驗證成功,修改區域隱藏,取消勾選,列表中是修改的數據:
21


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM