"如何系列" 关于 MVC、jQuery、JSON、分页、mapRoute






4.91/5 (85投票s)
"如何系列" 关于 MVC、jQuery、JSON、分页、mapRoute。
引言
由于数据库系统中有大量数据,客户端工作变得非常重要。在传统的 ASP.NET 中,代码隐藏的自然方法是使用 ASP.NET 组件在代码隐藏文件中编写大部分工作。此外,ASP.NET 组件的渲染和视图状态机制现在被认为是经典 ASP.NET 的薄弱之处。
因此,出现了一种新的范例。根据这种新范例,开发人员可以处理纯 HTML 和 JavaScript,减少渲染并避免影响性能的视图状态。
尽管 MVC 被认为是一种古老的设计或架构模式,但它尤其在提到上述经典 ASP.NET 的瓶颈之后而变得流行。在 MVC 中有效利用 jQuery 和 JSON 可以开发出高性能的应用程序。
背景
在阅读了一些关于 MVC、jQuery 和 JSON 的初级文章后,本文可能会有所帮助。以下链接可能对初学者有用:
- MVC 入门: https://w3schools.org.cn/aspnet/mvc_intro.asp
- jQuery 入门: https://w3schools.org.cn/jquery/default.asp
- JSON 入门: https://w3schools.org.cn/json/default.asp
使用代码
本文旨在提供一个“如何系列”。因此,所有脚本都来自附加的源代码。事实上,每个“如何”都可以成为一篇独立的文章。无论如何,所有可能的答案都收集在一个示例中。本文中的实际方法多于理论知识。为了简化示例,使用了一些静态列表而不是数据库。
以下问题将得到解答:
- 如何在 MVC 中实现高性能的 CRUD 操作?
- 如何使用 jQuery 对话框代替 JavaScript 的 confirm 或 alert?
- 如何在 MVC 列表中实现分页?
- 如何在 MVC 中使用“显示更多”链接?
- 如何在链接中使用属性?
- 如何在 jQuery 中进行 AJAX 调用?
- 如何在 MVC 中使用 Form collection?
- 如何一次删除多条记录?
- 如何在 MVC 中使用部分视图操作(partial action)?
- 如何在 MVC 应用程序中使用 JSON 格式?
- 如何填充主从组合框(master-detail combobox)?
- 如何使用 jQuery datepicker?
- 如何在 MVC 中使用 jQuery 对话框上传图片?
- 如何在客户端创建表格行?
- 如何自定义 `Global.asax` 中的 `mapRoute`?
- 如何实现表格行的全选和全不选
- 如何显示“正在加载数据”
- 如何使用 jQuery 创建主从表格(master-detail grids)?
1) 如何在 MVC 中实现高性能的 CRUD 操作?
粗略考虑,所有业务解决方案都具有创建-读取-更新-删除(CRUD)的特性。如果可能,从开发者的角度来看,为“插入”和“更新”使用相同的“保存表单”可能更具成本效益。通过管理发送到操作的参数,可以使用相同的表单。
假设你有一个类似表格的列表,实际上是一个 HTML 表格,并在表单上有一个单独的“新建”按钮。在表格的每一行中,都有一个与该行相关的“编辑”和“删除”按钮。
点击“新建”后,重定向到一个新页面——这里称为视图——并不是一个有效的方法。因为在重定向页面上保存数据后,用户必须点击“显示列表”才能看到插入到数据库中的数据。这意味着重定向列表视图并以可变的查询成本从数据库中选择数据!
而不是上面描述的“点击新建,然后再次列出”的场景,可以执行更好的方法。
Create(创建):
- 在列表视图中,点击“新建”后,会出现一个“jQuery 保存对话框”。
- Create 视图被渲染到 jQuery 对话框中。
- 填写 Create 表单并点击“保存”。
- 在点击保存按钮时,可以通过 AJAX POST 将数据发送到相关控制器。
- Ajax 表单有一个 `onSuccess` JavaScript 函数。
- 在“`onSuccess`”JavaScript 方法中,添加的新行(作为传递给“`onSuccess`”的参数 JSON)会被插入到列表中,而无需刷新整个列表。
Read(读取):
这是一个列表操作。如果可能,列表表单上应只显示所需数据。可以使用以下技术:
- 通过组合框或数字进行分页,
- 实现“显示更多”
- 带有过滤条件的列表。
Update(更新):
- 在列表视图中,点击列表中任意行的“编辑”后,会出现相同的“jQuery 保存对话框”,并显示选中行的数据。
- 因为所有步骤都与“创建”相同,所以只需要根据“更新”操作修改“`onSuccess`”方法。
- 在这种情况下,在数据库更新后,视图中只有被编辑的行的数据会被更新。通过这种方式,无需刷新整个列表即可查看最近编辑的记录。
Delete(删除):
- 在用一个漂亮的 jQuery 对话框确认后,在数据库删除后,只有选中行会从列表中移除。同样,无需刷新整个列表。
同一个对话框用于插入和编辑。

链接在 `PersonList.cshtml` 视图中如下:
@Html.ActionLink("New", "Save", 
  new { personNo = 0 }, new { @class = "newLink" })
 
...
 
@Html.ActionLink("Edit", "Save", new { personNo = item.PersonNo }, new { @class = "editLink" })
- New:要显示的文本。
- Save:控制器中的操作。
- personNo :作为参数传递给“Save”操作。** 如果为 0,则对话框将为空;如果大于 0,则在对话框中显示该 ID 的数据。
- newLink:在下面的 jQuery 中使用的虚构类名。
<div id="saveDialog" title="Person Information"></div>
 
<script type="text/javascript">
 
    var linkObj;
 
    //.....
    $(document).ready(function () {
 
       //...
        $('#saveDialog').dialog({
            autoOpen: false,
            width: 400,
            resizable: false,
            modal: true,
            buttons: {
                "Save": function () {
                    $("#update-message").html('');
                    $("#savePersonForm").submit();
                },
                "Cancel": function () {
                    $(this).dialog("close");
                }
            }
        });
 
 
       //....
       setLinks();
 
    });
 
    // ....
  
    function setLinks() 
    {
 
        $(".editLink, .newLink, uploadPicLink").unbind('click');
        $(".editLink, .newLink").click
        (
            function () 
            {
                linkObj = $(this);
                var dialogDiv = $('#saveDialog');
                var viewUrl = linkObj.attr('href');
                $.get(viewUrl, function (data) 
                {
                    dialogDiv.html(data);
                    //validation
                    var $form = $("#savePersonForm");
                    $form.unbind();
                    $form.data("validator", null);
                    $.validator.unobtrusive.parse(document);
                    $form.validate($form.data("unobtrusiveValidation").options);
                    dialogDiv.dialog('open');
                });
                return false;
            }
        );
 
        //...
 
    } //end setLinks
</script>
`PersonController` 中的 Save 操作如下:
// ...
[HttpGet]
public ActionResult Save(int personNo)
{
            
  Person person= new Person();
  person.BirthDate = DateTime.Today;
  person.PersonNo = 0;
            
  if (personNo > 0)
  {
     person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
  }
 
  return PartialView(person);
 
}
 
 // ...  
[HttpPost]
public JsonResult Save(Person p)
{
     //...
}
// ...
2) 如何使用 jQuery 对话框代替 JavaScript 的 confirm 或 alert?
在 Windows 应用程序中可以使用自定义的消息框。对于 Web,可以使用第三方组件库来实现。也可以使用 jQuery 对话框代替 JavaScript 的对话框,如下所示:

`PersonList` 视图中的 Delete 链接如下:
@Html.ActionLink("Delete", "DeletePerson", new { personNo = 
item.PersonNo }, new { @class = "deleteLink", @pkNo = item.PersonNo })
HTML 和 jQuery 代码如下:
<div id="confirmDialog" title="Warning"></div>
 
<script type="text/javascript">
//...
 
 $(".deleteLink").live("click", function (e) {
        e.preventDefault();
        // ..
        
        $("#confirmDialog").html('<br/><br/>sure?');
        $("#confirmDialog").dialog({
            resizable: false,
            height: 200,
            width: 300,
            modal: true,
            buttons: {
                "Yes": function () {
                    // ..
                 }, // end of yes button
                "No": function () {
                    $(this).dialog("close");
                }
            } //end buttons
        }); //end modal 
    });     //end delete
 
//...  
</script>
3) 如何在 MVC 列表中实现分页?
分页是列出数据和最小化数据传输成本的良好方法之一。可以执行许多显示数据的方法。在本“如何”中,使用组合框进行分页。但是,如果需要,可以在页面底部显示数字。这取决于应用程序和开发人员。可以使用组合框进行分页,如下所示:

首先,为分页元数据安排好位置,如下所示:
@model AddressBook_mvc3_jQuery.Models.Paginginfo
...
 
<div id="paginginfo">
<hr />
    <select id="PageSelect"></select>
    
    <span class="pagingPersonNo" style="visibility:hidden">@Model.id</span>
    <span class="pagingTotalCount" style="visibility:hidden">@Model.TotalCount</span>
    <span class="pagingPageSize" style="visibility:hidden">@Model.PageSize</span>
 
    <span class="pagingSummary">aaa</span>
 
<hr/>
</div>
 
<div id="content"></div>
 
...
在页面首次加载时,使用以下脚本填充 ID 为“`paginginfo`”的 div 并显示第一页记录:
<script type="text/javascript">
 
//...
  function initializePaging()
  {
       var PersonNo = $("#paginginfo .pagingPersonNo").text();
       var TotalCount = $("#paginginfo .pagingTotalCount").text();
       var PageSize = $("#paginginfo .pagingPageSize").text();
       
       var PageSelect = $("#PageSelect");
 
       if (TotalCount==0)
       {
            PageSelect.html("");
            $("#paginginfo").hide();
       }
       else
       {
             PageSelect.html("");
 
             var num = Math.ceil(TotalCount/PageSize);
 
             for (var i = 1; i <= num; i++) 
             {             
                if (i==1)
                    PageSelect.append($("<option selected></option>").val(i).text(i));
                else
                    PageSelect.append($("<option></option>").val(i).text(i));
             }
      }
        
      fillData(PersonNo, 1); 
 
  }
 
//.. 
 function fillData(parPersonNo, parPageNo) 
 { 
    if (parPageNo) 
    {
        $.ajax({
            type: "POST", 
            url: "@Url.Action("GetAddressList", "Address")",
            data: { personNo: parPersonNo, pageNo: parPageNo },
            cache: false,
            dataType: "json",
            success: function (data) 
            {                                  
                if (data.Html) 
                {                       
                    $("#content").html(data.Html);
                    
                    buttonizeALL();
                    setLinkAbilites();
                    
                    setPagingSummary(parPageNo);
                }
                else 
                {
                    alert('opps!'); 
                }
            },
            error: function(exp)        
            {
                     alert('Error address : ' + exp.responseText);
            }                
        }); //end ajax call
    } // if (parPageNo) 
  }//fillData
//...
</script>
控制器中的操作代码如下。可以看到,结果列表被部分渲染并使用 `RenderPartialView` 方法放入 JSON 对象中。
public class AddressController : Controller
{
  //..
  public JsonResult GetAddressList(int personNo, int pageNo)
  {
        
        int pageSize = 5; //it could be parameter
        int skipCnt = ((pageNo - 1) * pageSize);
        List<Address> list = (from x in Repository.GetAddressList() where x.PersonNo == 
          personNo orderby x.AddressNo descending select x).Skip(skipCnt).Take(pageSize).ToList();
       
        JsonResult jr = Json(new
        {
            Html = this.RenderPartialView("AddressList", list),
            Message = "OK"
        }, JsonRequestBehavior.AllowGet);
        return jr;
  }
  //..
}
当 ID 为“`PageSelect`”的组合框的 `selecteditem` 发生变化时,将运行以下 jQuery 脚本:
//..
    $("#PageSelect").change(function () 
    {
 
        var $this = $(this);
        var parPageNo = $this.val();
 
        var parPersonNo = $("#paginginfo .pagingPersonNo").text();
 
        fillData(parPersonNo,parPageNo);
                      
    });//PageSelect
//..
4) 如何使用 jQuery 实现“显示更多”链接?
这项技术在许多流行的网站中都有使用。它应该在大列表上执行。“显示更多”可以按如下方式实现:

列表视图有一个“更多”链接。
//
 
<table id="NoteTable"></table>
 
<br />
<a href="#"  style="display:none"  id="more">more</a>
 
<div id="saveDialog" title="Notes Information"></div>
<div id="confirmDialog" title="Warning"></div>
 
//
点击“更多”后,将运行以下 jQuery 脚本:
//..
   //load more results
    $(function () 
    {
        $("#more").click(function (e) 
        {
            e.preventDefault();
                       
            var lastNoteNo = $("#NoteTable tr:last .noteNo").text();
            if (lastNoteNo) 
            {
                var PersonNo = $("#paginginfo .pagingPersonNo").text();
                fillData(PersonNo, lastNoteNo); 
            }
 
            //--- scroll to bottom of page ---
            var $target = $('html,body'); 
            $target.animate({scrollTop: $target.height()}, "slow");
            //--- /scroll to bottom of page ---
            return false;
        });
    });
 
//..
 
   function fillData(parPersonNo, parLastNoteNo) 
    {                 
        if (parPersonNo) 
        {
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetNoteList", "Note")",
                data: { personNo: parPersonNo,  lastNoteNo: parLastNoteNo} ,
                cache: false,
                dataType: "json",
                success: function (data) 
                {
                    if (data.Html) 
                    {
                        $("#NoteTable").append(data.Html);
                        
                        buttonizeALL();
                        setLinkAbilites();
                        
                        if (data.HasMore)
                            $("#more").show();
                        else                        
                            $("#more").hide();
                    }
                    else 
                    {
                        alert('opps!'); 
                    }
                },                
                error: function(exp)        
                {
                        alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
        } // if 
    }//func
// ..
控制器中的以下操作返回 JSON 结果:
public class NoteController : Controller
{
   //...
    public JsonResult GetNoteList(int personNo,  int lastNoteNo)
    {
        int pageSize = 5; //it could be parameter
        bool hasMore = false;
        List<Note> list = null;
        if (lastNoteNo == 0)
        {            
            list = (from x in Repository.GetNoteList() where x.PersonNo == personNo 
              orderby x.NoteNo descending select x).Take(pageSize).ToList();
            hasMore = (from x in Repository.GetNoteList() where x.PersonNo == 
              personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
        }
        else
        {
            list = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo && 
              x.PersonNo == personNo orderby x.NoteNo descending select x).Take(pageSize).ToList();
            hasMore = (from x in Repository.GetNoteList() where x.NoteNo < lastNoteNo && 
              x.PersonNo == personNo select x.NoteNo).Take(pageSize + 1).Count() - pageSize > 0;
        }
        
        JsonResult jr = Json(new
        {
            Html = this.RenderPartialView("_NoteList", list),
            Message = "OK",
            HasMore = hasMore
        }, JsonRequestBehavior.AllowGet);
        return jr;
    }
  // ...
}
5) 如何在链接中使用属性?
这是一种很好的能力,尤其适用于按钮,例如编辑、删除、显示详情等。
在创建列表时,将相关键作为属性附加到链接。点击链接事件时,可以使用该键轻松完成操作。
例如,假设列表中的每一行都有一个删除链接。当点击行中的删除链接时,可以使用该键作为控制器中“删除操作”的参数。
@Html.ActionLink("Delete", "DeletePerson", new { personNo = item.PersonNo }, 
  new { @class = "deleteLink", @pkNo = item.PersonNo })
在客户端检查源代码时,会看到以下行:
<a role="button" class="deleteLink ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" 
  href="https://codeproject.org.cn/Person/DeletePerson/1" pkno="1"><span class="ui-button-text">Delete</span></a>
  在 jQuery 脚本中,属性的使用如下。例如,pkno 为 1 并被使用。
$(".deleteLink").live("click", function (e) 
{
      e.preventDefault();
      var pkNo = $(this).attr("pkNo");
      //..
});
6) 如何在 jQuery 中进行 AJAX 调用?
AJAX 调用是提高应用程序速度的一个非常好的能力。在一些数据库数据量大的应用程序中,开发人员必须注意两条数据线上的低数据传输量。第一条线是数据库和应用程序之间,第二条线是应用程序和客户端浏览器之间。对于这类需求,AJAX 调用非常有用。
//..
  $.ajax({
            type: "POST",
            url: "/Person/DeletePerson", 
            data: { personNo: pkNo },
            cache: false,
            dataType: "json",
            success: function () 
            {
                       //.. 
            },
            error: function (jqXHR, exception) 
            {
                 alert('Uncaught Error.\n' + jqXHR.responseText);
            }
         }); //end ajax call
//..
URL 也可以像这样使用:
//..
url: "@Url.Action("DeletePerson", "Person")",
 
// ..
7) 如何在 MVC 中使用 Form collection?
提交表单时,所有表单元素都作为集合发送到控制器中的相关操作。
在控制器中,可以使用每个键值对。假设你有一个如下的保存表单:
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" name="TBPersonNo" 
      id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" name="TBAddressNo" 
      id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
          id="idTBAddressText">@Model.AddressText</textarea>            
        </td>
        </tr>
        </table>        
    </fieldset>
}
视图中的数据可以作为模型对象或 FormCollection 提交到控制器中的操作,如下所示:
//..
 
[HttpPost]
public JsonResult Save(FormCollection fc)
{
    object obj = null;
                
    Address addrTmp = new Address();
    addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
    addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
    addrTmp.AddressText = fc["TBAddressText"].ToString();
    addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
    addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString()); 
    
    if (ModelState.IsValid)
    {
        if (addrTmp.AddressNo == 0)
        {
            //find last person 
            //if it is database system no need to this line. Probably the AddressNo would be autoincrement
            addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;
            Data.Repository.GetAddressList().Add(addrTmp);
            
            obj = new { Success = true, 
                        Message = "Added successfully", 
                        Object = addrTmp, 
                        operationType = "INSERT", 
                        Html = this.RenderPartialView("_addressLine", addrTmp )
                      };
        }
        else
        {
            Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
            addr.AddressTypeNo = addrTmp.AddressTypeNo;
            addr.AddressText = addrTmp.AddressText;
            addr.CityNo = addrTmp.CityNo;
            addr.PersonNo = addrTmp.PersonNo;
            obj = new { Success = true, 
                        Message = "Updated successfully", 
                        Object = addr, 
                        operationType = "UPDATE",
                        Html = this.RenderPartialView("_addressLine",  addr )
                      };
        }                
    }
    else
    {
        obj = new { Success = false, Message = "Please check form" };
    }
    return Json(obj, JsonRequestBehavior.DenyGet);
}
 
//..
8) 如何一次删除多条记录?
在某些页面上,一次删除多条记录有时可以使业务更容易。通过收集所有选定记录的键,可以删除多条记录。将所有键发送到控制器后,可以按如下方式执行删除:

首先点击带有“`deleteALL`”ID 的“Delete Selected”按钮。点击“Yes”后,可以使用以下 jQuery 脚本。当然,也可以开发替代脚本。
//..
$("#deleteALL").live("click", function (e) 
{
    e.preventDefault();
    
    var len = $("#NoteTable tr").length;
    
    $("#confirmDialog").html('<br/><br/>deleting all selecteds.. sure?');
    $("#confirmDialog").dialog({
        resizable: false,
        height: 200,
        width: 300,
        modal: true,
        buttons: 
        {
            "Yes": function () 
            {
                $(this).dialog("close");
                
                    var strSelecteds = '';
                    var rows = $("#NoteTable tr");
                    for(var i=0; i< rows.length; i++)
                    {                               
                        var row = $(rows).eq(i);
                        var span = row.find('span#cboxSpan');
                        var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
                        
                        var checked=(cb.is(':checked'));
                        var pkno =  cb.attr("pkno"); 
                        if (checked)
                        {
                            strSelecteds = strSelecteds + pkno + ',';
                        }
                    }//
                            
                    if (strSelecteds.length>0)
                    {
                        strSelecteds = strSelecteds.substring(0,strSelecteds.length-1);
                    }
                    
                    if (strSelecteds.length>0)
                    {
                        $.ajax({
                            type: "POST",
                            url: "/Note/DeleteALL",   
                            data: { noteNOs: strSelecteds },
                            cache: false,
                            dataType: "json",
                            success: function (data) 
                            {
                                var  strSelectedsArr = strSelecteds.split(',');
                                for (var i = 0; i < strSelectedsArr.length; i++) 
                                {
                                    var rowNo = '#row-' + strSelectedsArr[i];
                                    $(rowNo).remove();  
                                    //alert(strSelectedsArr[i]);
                                }//for
                                
                                $('#saveDialog').dialog('close');
                                $('#Message').html(data.Message);
                                $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);
                            },                          
                            error: function(jqXHR, exception) 
                            {
                                alert('Uncaught Error.\n' + jqXHR.responseText);
                            }
                        }); //end ajax call
                    }
                    else
                        alert('No row selected');
            }, // end of yes button
            "No": function () 
            {
                $(this).dialog("close");
            }
        } //end buttons
    }); //end modal 
});    //end deleteALL
 
//...
如上所示,通过 AJAX 调用“Note”控制器中的“DeleteALL”操作,可以删除多条记录。
9) 如何在 MVC 中使用部分视图操作(partial action)?
在某些情况下,需要在多个表单上使用一个组件。例如,你可能需要在一些单独的表单上有一个“人员信息框”,如下所示:

`_personinfo` 视图可以如下:
@model AddressBook_mvc3_jQuery.Models.Person
 
@{ ViewBag.Title = "_personinfo"; }
           
<fieldset>
    <legend>Person info</legend>
 
    <table>
<tr><td><b><span> @Model.FirstName @Model.LastName </span></b>(@String.Format("{0:dd.MM.yyyy}", 
  Model.BirthDate))</td><td>(@Model.CategoryName)</td></tr>
    </table>
 
</fieldset>
在任何视图中使用部分视图操作,可以使用以下代码行:
//..
 
<h2>Address List</h2>
<div> 
    @Html.Action("_personinfo", "Common") 
</div> 
 
//..
10) 如何在 MVC 应用程序中使用 JSON 格式?
在向控制器操作发送参数和从操作获取结果时,可以使用 JSON 格式。如下所示,Note 控制器中的 DeleteNote 操作有一个 noteNo 参数。这里,pkNo 是一个值传递参数。
$(".deleteLink").live("click", function (e) 
{
    e.preventDefault();
    var pkNo = $(this).attr("pkNo");
    //..
    $.ajax({
             type: "POST",
             url: "/Note/DeleteNote",
             data: { noteNo: pkNo },
             cache: false,
             dataType: "json",
             success: function () 
             {
               $(rowNo).remove();
             },
             error: function(jqXHR, exception) 
             {
                alert('Uncaught Error.\n' + jqXHR.responseText);
             }
            }); //end ajax call
    //.. 
});    //end delete
可以从控制器操作获取 JSON 结果。以下脚本以 JSON 对象的形式返回结果:
//..
 
[HttpPost]
public JsonResult DeleteNote(int noteNo)
{
    string message = string.Empty;
    try
    {
        Note n = Data.Repository.GetNoteList().Where(c => c.NoteNo == noteNo).FirstOrDefault();
        if (n != null)
        {
            Data.Repository.GetNoteList().Remove(n);
            message = "Deleted";
        }
        else
        {
            message = "Note not found!";
        }
    }
    catch (Exception ex)
    {
        message = ex.Message;
    }
    return Json(new { Message = message }, JsonRequestBehavior.AllowGet);
}
 
//..
11) 如何填充主从组合框(master-detail combobox)?
某些表单要求在更改一个组合框时填充另一个组合框。例如,对于国家-城市对,国家可以被认为是主,城市是次。

“保存表单”视图中的 HTML 如下:
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" name="TBPersonNo" 
      id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" name="TBAddressNo" 
      id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">  
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px"> 
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
          id="idTBAddressText">@Model.AddressText</textarea>
        </td>
        </tr>
        </table>        
    </fieldset>
}
首次加载时,使用 Address 控制器中的“GetCountryList”操作填充 idCBCountry 组合框。然后,在更改国家组合框时,按如下方式填充城市组合框:
<script type="text/javascript">
 
    $(document).ready(function () {  
 
    //...
    //-----------------------------------------------------
    
                
   $.ajax({
        type: "POST",
        url: "@Url.Action("GetCountryList", "Address")",
        data: {},
        cache: false,
        dataType: "json",
        success: function (data) 
        {                               
             var idCBcountry = $("#idCBcountry");
             idCBcountry.html("");
                    
              if (@Model.AddressNo>0)
              {
                 for (var i = 0; i < data.List.length; i++) 
                 {
                    var item = data.List[i];
                    if (item.CountryNo == @Model.CountryNo)
                    {                                
                        idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
                        fillCity(item.CountryNo);
                    }
                    else
                    {
                        idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
                    }
                 }  //for   
              }      
              else
              {
                    for (var i = 0; i < data.List.length; i++) 
                     {
                        var item = data.List[i];
                        if (i==0)
                        {
                            idCBcountry.append($("<option selected></option>").val(item.CountryNo).text(item.CountryName));
                            fillCity(item.CountryNo);
                        }
                        else
                        {
                            idCBcountry.append($("<option />").val(item.CountryNo).text(item.CountryName));
                        }
                     }  //for
              }//else
            },  
            error: function(exp)        
            {
                 alert('ErrorCountry : ' + exp.responseText);
            }
        });
 
        //-----------------------------------------------------
            $("#idCBcountry").change(function () {
                var $this = $(this);
                var CountryNo = $this.val();
                if (CountryNo) 
                {
                    fillCity(CountryNo);
                }//if
            });
            //-----------------------------------------------------
});//end of function
 
function fillCity(parCountryNo)
{
    $.ajax({
        type: "POST",
        url: "@Url.Action("GetCityList", "Address")",
        data: {CountryNo: parCountryNo},
        cache: false,
        dataType: "json",
        success: function (data) 
        {
             var idCBcity = $("#idCBcity");
             idCBcity.html("");
             for (var i = 0; i < data.List.length; i++) 
             {
                var item = data.List[i];
                if (item.CityNo == @Model.CityNo)
                {
                    idCBcity.append($("<option selected></option>").val(item.CityNo).text(item.CityName));
                }
                else
                {
                    idCBcity.append($("<option />").val(item.CityNo).text(item.CityName));
                }
             }
        },
        error: function(exp)        
        {
             alert('ErrorCity : ' + exp.responseText);
        }
    });
}//fillCity
</script>
操作代码如下。列表被嵌入到 JSON 对象中。然后,在上面显示的 jQuery 脚本中,列表元素使用索引来访问。
public class AddressController : Controller
{
    //..
    public JsonResult GetCountryList()
    {
        object obj = null;
        List<Country> list = Repository.GetCountryList();
        obj = new { Success = true, Message = "OK", List = list };
        return Json(obj, JsonRequestBehavior.AllowGet);
    }
   
    public JsonResult GetCityList(int CountryNo)
    {
        object obj = null;
        List<City> list = Repository.GetCityList().Where(c => c.CountryNo == CountryNo).ToList(); ;
        obj = new { Success = true, Message = "OK", List = list };
        return Json(obj, JsonRequestBehavior.AllowGet);
    }
   //..
}
此技术可用于视图表单上的任何 HTML 元素。
12) 如何使用 jQuery datepicker?
日期类型几乎用于所有业务应用程序。由于文化差异,有时使用此类型会对开发人员造成麻烦。但是,jQuery datepicker 使日期类型的处理变得容易。

要在列表中以所需格式显示日期,可以使用以下行:
<span class="BirthDate"> @String.Format("{0:dd.MM.yyyy}", item.BirthDate) </span>
在保存表单中,使用以下 HTML 脚本:
  ...
       
    <div class="editor-label">
        @Html.LabelFor(model => model.BirthDate)
    </div>
    <div class="editor-field">         
        @Html.TextBoxFor(model => model.BirthDate, 
                new { @class = "BirthDateSave", 
                      @id = "TBBirthDate",
                      @Value = Model.BirthDate.ToString("dd.MM.yyyy") 
                    })
    </div>
   ...jQuery Datepicker 可以与 @Html.TextboxFor 一起使用,使用同一页面上的以下脚本:
<script language="javascript" type="text/javascript">
 
 $(document).ready(function () {
    $(".BirthDateSave").datepicker({  
             changeMonth: true,
             changeYear: true,  
             dateFormat: 'dd.mm.yy',
             showOn: 'both'
                   });  
                });
</script>必须在适当的 .cshtml 文件开头包含以下行:
..
  <link href="@Url.Content("~/Content/themes/base/jquery.ui.all.css")" rel="stylesheet" type="text/css" />
  <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>    
  <script src="@Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
..
13) 如何在 MVC 中使用 jQuery 对话框上传图片?
可以在单独的视图中轻松上传图片。但是,仅为上传图片而重定向到单独的视图,然后再次重定向到列表视图,从成本角度来看可能效率低下。因此,相反,在列表视图中,可以通过点击每行的上传链接打开一个 jQuery 对话框,然后浏览并上传图片。

点击“Upload Pic”后,将运行以下脚本:
//..
$(".uploadPicLink").click
(
    function () 
    {
        linkObj = $(this);
        var dialogDiv = $('#savePicDialog');
        var viewUrl = linkObj.attr('href');
        $.get(viewUrl, function (data) {
            dialogDiv.html(data);
            //validation
            var $form = $("#savePersonPicForm");
            $form.unbind();
            $form.data("validator", null);
            $.validator.unobtrusive.parse(document);
            $form.validate($form.data("unobtrusiveValidation").options);
            dialogDiv.dialog('open');
        });
        return false;
    }
);
//..
加载到 jQuery 对话框中的 SavePersonPic 表单如下。iframe 用于在 jQuery 对话框中上传文件。
@model AddressBook_mvc3_jQuery.Models.Person            
@{ViewBag.Title = "Save image";}
@using (Html.BeginForm("SavePersonPic", "Person", FormMethod.Post,
             new
             {
                enctype = "multipart/form-data",        
                id = "savePersonPicForm",
                name = "savePersonPicForm",
                target = "UploadTarget"
              }))        
{
    @Html.ValidationSummary(true)    
    
    <div id="update-message" class="error invisible"></div>    
    <fieldset>
        <legend>Person Picture</legend> 
        <div class="editor-label">
            <label for="file">Upload Image:</label>
        </div>
        <div class="editor-field">
            <input type="file" name="file" id="file"/>        
        </div>      
 
    </fieldset>        
}
<iframe id="UploadTarget" 
   name="UploadTarget" onload="UploadImage_Complete();" 
        style="position: absolute; left: -999em; top: -999em;">
</iframe>
控制器中用于上传文件的操作如下:
public class PersonController : Controller
{
    //..
    //-------------- image -----
    [HttpGet]
    public ActionResult SavePersonPic(int personNo)
    {
        Person person = new Person();
                    
        if (personNo > 0)
        {
            person = Repository.GetPersonList().Where(c => c.PersonNo == personNo).FirstOrDefault();
        }
        return PartialView(person);
    }
 
    [HttpPost]        
    public JsonResult SavePersonPic(HttpPostedFileBase file,   int personNo)
    {                
        string message = string.Empty;
        bool success = false;
        string imgPath = "";
        string fileName = "";
        try
        {
            string path = System.IO.Path.Combine(Server.MapPath("~/Content/images"), 
                            System.IO.Path.GetFileName(file.FileName));
            file.SaveAs(path);
            Person p = Data.Repository.GetPersonList().Where(r => r.PersonNo == personNo).FirstOrDefault();
            p.imgFileName = file.FileName;
            ViewBag.Message = "File uploaded successfully";
            message = ViewBag.Message;
            fileName = file.FileName;
            imgPath = Url.Content(String.Format("~/Content/images/{0}", fileName)); 
            
            success = true;
        }
        catch (Exception ex)
        {
            message = ex.Message;
            success = true;
            imgPath = "";
            fileName = "";
        }
 
        return Json(
                        new { Success = success, 
                              Message = message, 
                              PersonNo=personNo,
                              ImagePath = imgPath,
                              FileName = fileName
                            }, 
                        JsonRequestBehavior.AllowGet
                    );
    }
    //------------- /image --------
    // ..
}
iframe 的 JavaScript “onload”函数如下。上传的图片会在列表的相应行中显示,而无需刷新该行。
//..
function UploadImage_Complete() 
{            
    //Check first load of the iFrame
    if (isFirstLoad == true) 
    {
        isFirstLoad = false;
        return;
    }
    try 
    {            
        //Reset the image form
        document.getElementById("savePersonPicForm").reset();
    
        var jsonTxt = ($('#UploadTarget').contents()).text();            
        var jsonObj = JSON.parse(jsonTxt);
        
        var rowid = '#row-' + jsonObj.PersonNo;            
        var row = $('#personTable ' + rowid);           
        var imgid = "#img-" + jsonObj.PersonNo;
        var img = row.find(imgid);
            $(img).attr("src", jsonObj.ImagePath);
       
        $('#Message').html(jsonObj.Message);
        $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300)
        $('#savePicDialog').dialog('close');
    }
    catch (err) 
    {
        alert(err.get_Message());
    }
}
 
//..
14) 如何在客户端创建表格行?
添加到数据库的记录应该在客户端的列表中显示。这可以通过多种方式完成。添加记录后,可以从数据库完全刷新列表,但这会导致繁重的操作。然而,使用 JavaScript 或 jQuery,可以在不刷新视图上的所有元素的情况下,将新行添加到列表中。这里提到了两种方法。
第一种方法,即逐行逐单元格地由 JavaScript 创建行和单元格,如下所示。从下面的脚本可以看出,在提交此表单后,使用 **saveSuccess** JavaScript 函数来处理这种情况:
..
 
@model AddressBook_mvc3_jQuery.Models.Person
            
@{  ViewBag.Title = "Save Person"; }
 
..
 
@using (Ajax.BeginForm("Save", "Person", new AjaxOptions
{
    InsertionMode = InsertionMode.Replace,
    HttpMethod = "POST",
    OnSuccess = "saveSuccess"    
}, new { @id = "savePersonForm" }))
{
    @Html.ValidationSummary(true)    
    
    ..        
}
 
..
**saveSuccess** JavaScript 方法如下。操作返回一个包含操作类型的 JSON 结果。根据操作(INSERT 或 UPDATE),会修改视图上的表格。当一条新记录添加到数据库时,新的一行会被添加到表格的开头。当一条现有记录在数据库中被更新时,表格中只有相关的行会被修改。
..
 
function saveSuccess(data) 
{
    if (data.Success == true) 
    {
        if (data.operationType == 'UPDATE') 
        {
            //we update the table's row info
            var parent = linkObj.closest("tr");
            $(parent).animate({ opacity: 0.3 }, 200, function () {;});
            parent.find(".FirstName").html(data.Object.FirstName);
            parent.find(".LastName").html(data.Object.LastName);
            parent.find(".CategoryName").html(data.Object.CategoryName);
            var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
            var dateStr = FormatDate(date);
            parent.find(".BirthDate").html(dateStr);
            $(parent).animate({ opacity: 1.0 }, 200, function () {;});
        }
        else 
        {  //INSERT
            //we add the new row to table
            //we do not refresh all records on screen
            
            try 
            {                    
                var personTable = document.getElementById("personTable");
                var row = personTable.insertRow(1); //row 0 is header
                row.setAttribute("id", 'row-' + data.Object.PersonNo.toString());
                var buttonsLinks =
                '<a role="button" class="editLink ui-button ui-widget ui-state-default ui-corner-all ' + 
                'ui-button-text-only ui-state-hover ui-state-focus" href="https://codeproject.org.cn/Person/Save/' + 
                data.Object.PersonNo.toString() + '"><span class="ui-button-text">Edit</span></a> ' +
                '<a role="button" class="adressLink ui-button ui-widget ui-state-default ui-corner-all ' + 
                'ui-button-text-only" href="https://codeproject.org.cn/Address/Index/' + data.Object.PersonNo.toString()  + 
                '"><span class="ui-button-text">Addresses</span></a> ' +
                '<a role="button" class="noteLink ui-button ui-widget ui-state-default ui-corner-all ' + 
                'ui-button-text-only" href="https://codeproject.org.cn/Note/Index/' + data.Object.PersonNo.toString() + 
                '"><span class="ui-button-text">Notes</span></a> ' +
                '<a role="button" class="deleteLink ui-button ui-widget ui-state-default ' + 
                'ui-corner-all ui-button-text-only" href="https://codeproject.org.cn/Person/Delete/' + 
                data.Object.PersonNo.toString() + '" pkno="' + data.Object.PersonNo.toString()  + 
                '"><span class="ui-button-text">Delete</span></a>';
        
                var cellButtons = row.insertCell(0);
                cellButtons.innerHTML = buttonsLinks;
                var cellPersonNo = row.insertCell(1);
                cellPersonNo.innerHTML = "<span  class=\"PersonNo\">" + 
                  data.Object.PersonNo + "</span>";
                var cellCategoryName = row.insertCell(2);
                cellCategoryName.innerHTML = "<span  class=\"CategoryName\">" + 
                  data.Object.CategoryName + "</span>";
                var cellFN = row.insertCell(3);
                cellFN.innerHTML = "<span  class=\"FirstName\">" + 
                  data.Object.FirstName + "</span>";
            
                var cellLN= row.insertCell(4);
                cellLN.innerHTML = "<span  class=\"LastName\">" + 
                  data.Object.LastName + "</span>";
                var cellBirthDate = row.insertCell(5);
                var date = new Date(parseInt(data.Object.BirthDate.substr(6)));
                var dateStr = FormatDate(date);
                cellBirthDate.innerHTML = "<span  class=\"BirthDate\">" + 
                  dateStr + "</span>";
                var cellimgFileName = row.insertCell(6);
                cellimgFileName.innerHTML =
                    "<img id=\"img-" + data.Object.PersonNo.toString() + "\" alt=\"" + 
                      data.Object.ImgFileName + "\" src=\"/content/images/" + "noimg.jpg" + 
                      "\" height=\"35px\" width=\"50px\"><br><a " + 
                      "class=\"uploadPicLink\" href=\"/Person/SavePersonPic/" + data.Object.PersonNo.toString() + 
                      "\" pkno=\"" + data.Object.PersonNo.toString() + 
                      "\" style=\"font-size:9px;\">Upload Pic</a>";
                 
                setLinks();
            }
            catch (err) {
                alert(err.Message);
            }
        }
        
        $('#saveDialog').dialog('close');
        $('#Message').html(data.Message);
        $('#Message').delay(300).slideDown(300).delay(1000).slideUp(300);
    }
    else {
        $("#update-message").html(data.ErrorMessage);
        $("#update-message").show();
    }
} 
..
表格如下:
//..
 
<table id="personTable">
    <tr>
        <th></th>
        <th>
            #
        </th>
        <th>
            Category
        </th>
        <th>
            FirstName
        </th>
        <th>
            SecondName
        </th>
        <th>
            BirthDate
        </th>
        <th>
            image
        </th>
    </tr>
 
@foreach (var item in Model) {
    <tr id="row-@item.PersonNo">
        <td> 
            @Html.ActionLink("Edit", "Save", 
              new { personNo = item.PersonNo }, new { @class = "editLink" })
            @Html.ActionLink("Addresses", "Index", 
              "Address", new { personNo = item.PersonNo }, new { @class = "adressLink" }) 
            @Html.ActionLink("Notes", "Index", 
              "Note", new { personNo = item.PersonNo }, new { @class = "noteLink" }) 
            @Html.ActionLink("Delete", "DeletePerson", 
              new { personNo = item.PersonNo }, new { @class = "deleteLink", @pkNo = item.PersonNo })
        </td>
 
        <td>
            <span class="PersonNo">@item.PersonNo</span>
        </td>
        <td>
            <span class="CategoryName">@item.CategoryName</span>
        </td>
        <td>
            <span class="FirstName">@item.FirstName</span>             
        </td>
        <td>
            <span class="LastName">@item.LastName</span>
        </td>
        <td> 
            <span class="BirthDate"> @String.Format("{0:dd.MM.yyyy}", item.BirthDate) </span>
        </td>
        <td>
            <img  id="img-@item.PersonNo" height="35px" width="50px" 
              alt="@item.ImgFileName " src="https://codeproject.org.cn/content/images/@item.ImgFileName" />
            <br />
            @Html.ActionLink("Upload Pic", "SavePersonPic", new { personNo = item.PersonNo }, 
              new { @class = "uploadPicLink", @pkNo = item.PersonNo, style = "font-size:9px;" })
        </td>
    </tr>
}
 
</table>
 
//..
上面提到的第一种方法可能看起来是一种旧的方法。因此,以下**第二种方法**可能更可行。在这种方法中,使用渲染的 HTML 来添加或更新表格行。假设有一个如下的表格:
@model IEnumerable<AddressBook_mvc3_jQuery.Models.Address>
 
<table id="AddressTable">
    <tr>
        <th></th>
        <th>
            #
        </th>       
        <th>
            AddressType
        </th>
        <th>
            City/Country
        </th>
        <th>
            Address Text
        </th>        
    </tr>
 
@foreach (var item in Model) 
{
    <tr id="row-@item.AddressNo">
        <td>            
            @Html.ActionLink("Edit", "Save", 
              new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
            @Html.ActionLink("Delete", "DeleteAddress", 
              new { addressNo = item.AddressNo }, new { @class = "deleteLink", @pkNo = item.AddressNo })
        </td>
        <td>            
            <span class="AddressNo">@item.AddressNo</span>
        </td>       
        <td>            
            <span class="AddressTypeName">@item.AddressTypeName</span>
        </td>
        <td>            
            <span class="CityName">@item.CityName/@item.CountryName</span>
        </td>
        <td>            
            <span class="AddressText">@item.AddressText</span>
        </td>       
    </tr>
}
 
</table>
点击“新建”后,以下脚本会加载到一个 jQuery 对话框中:
@model AddressBook_mvc3_jQuery.Models.Address
@{ViewBag.Title = "Address"; }
 
@using (Ajax.BeginForm("Save", "Address", new AjaxOptions
                            {
                                InsertionMode = InsertionMode.Replace,
                                HttpMethod = "POST",
                                OnSuccess = "saveSuccess"
                            }, new { @id = "saveForm" }))
{
    @Html.ValidationSummary(true)
    <input style="visibility:hidden" type="text" 
      name="TBPersonNo" id="idTBPersonNo" value="@Model.PersonNo"/>
    <input style="visibility:hidden" type="text" 
      name="TBAddressNo" id="idTBAddressNo" value="@Model.AddressNo"/>
    
    <br />        
    <fieldset>       
        <table>        
        <tr>
        <td>Address Type</td>
        <td>        
          <select name="CBAddressType" id="idCBAddressType" style="width:120px">
          </select>
        </td>
        </tr>
        <tr>
        <td>Country</td>
        <td>            
            <select name="CBcountry" id="idCBcountry" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>City</td>
        <td>            
            <select name="CBcity" id="idCBcity" style="width:120px">
            </select>
        </td>
        </tr>
        <tr>
        <td>AddressText</td>
        <td>        
        <textarea rows="4" cols="25" name="TBAddressText" 
              id="idTBAddressText">@Model.AddressText</textarea>
        </td>
        </tr>
        </table>        
    </fieldset>
}
当表单提交时,将运行控制器中的以下操作:
public class AddressController : Controller
{
    //..
    [HttpPost]
    public JsonResult Save(FormCollection fc)
    {
        object obj = null;
        Address addrTmp = new Address();
        addrTmp.AddressNo = Convert.ToInt32(fc["TBAddressNo"].ToString());
        addrTmp.AddressTypeNo = Convert.ToInt32(fc["CBAddressType"].ToString());
        addrTmp.AddressText = fc["TBAddressText"].ToString();
        addrTmp.CityNo = Convert.ToInt32(fc["CBcity"].ToString()); ;
        addrTmp.PersonNo = Convert.ToInt32(fc["TBPersonNo"].ToString()); 
        
        if (ModelState.IsValid)
        {
            if (addrTmp.AddressNo == 0)
            {
                //find last person 
                //if it is database system no need to this line. Probably the AddressNo would be autoincrement
                addrTmp.AddressNo = Data.Repository.GetAddressList().OrderBy(x => x.AddressNo).Last().AddressNo + 1;
                Data.Repository.GetAddressList().Add(addrTmp);
                obj = new { Success = true, 
                            Message = "Added successfully", 
                            Object = addrTmp, 
                            operationType = "INSERT", 
                                Html = this.RenderPartialView("_addressLine", addrTmp )
                          };
            }
            else
            {
                Address addr = Repository.GetAddressList().Where(c => c.AddressNo == addrTmp.AddressNo).FirstOrDefault();
                addr.AddressTypeNo = addrTmp.AddressTypeNo;
                addr.AddressText = addrTmp.AddressText;
                addr.CityNo = addrTmp.CityNo;
                addr.PersonNo = addrTmp.PersonNo;
                obj = new { Success = true, 
                            Message = "Updated successfully", 
                            Object = addr, 
                            operationType = "UPDATE", 
                                Html = this.RenderPartialView("_addressLine",  addr )
                          };
            }                
        }
        else
        {
            obj = new { Success = false, Message = "Please check form" };
        }
        return Json(obj, JsonRequestBehavior.DenyGet);
    }
    // .. 
}
`RenderPartialView` 方法用于获取所需的 HTML 脚本。
//..
public static string RenderPartialView(this Controller controller, string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
    controller.ViewData.Model = model;
    using (var sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
        var viewContext = new ViewContext(controller.ControllerContext, 
               viewResult.View, controller.ViewData, controller.TempData, sw);
        viewResult.View.Render(viewContext, sw);
        return sw.GetStringBuilder().ToString();
    }
}
//..
saveAddress 表单中 AJAX POST 的 saveSuccess 函数如下:
<script type="text/javascript">
 
    //...
    function saveSuccess(data) 
    {
        if (data.Success == true) 
        {            
            $("#paginginfo").show();       
 
            if (data.operationType == 'UPDATE') 
            {                           
                var row = linkObj.closest("tr");
                
                // the following line can also be used  to get related row
                //$('#AddressTable #row-' + data.Object.AddressNo); 
                row.replaceWith(data.Html);  
                //..
            }
            else 
            {  //INSERT
                try 
                {                                
                      $("#AddressTable tr:first").after(data.Html);
 
                     //..
                }
                catch (err) 
                {
                       alert(err.Message);
                }
            }
            
            //..
        }
        else 
        {
           //..
        }
    }
 
    //..
    
</script>
上述两种技术中的任何一种都可以使用。
15) 如何自定义 `Global.asax` 中的 `mapRoute`?
在经典的 ASP.NET 应用程序中,URL 重写操作可以通过一些第三方程序集轻松完成。在 MVC 应用程序中,可以使用 `Global.asax` 来自定义 `mapRoutes`。
`Global.asax` 中的默认 maproute 如下:
public class MvcApplication : System.Web.HttpApplication
{
    //..
    public static void RegisterRoutes(RouteCollection routes)
    {
       // all new customized maproute rules can be put here
        
        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );
    }
    //  .. 
}根据以下脚本,**`/Save/{addressNo}/{personNo}`** 被用作链接。
@Html.ActionLink("Edit", "Save", 
  new { addressNo = item.AddressNo, personNo = item.PersonNo }, new { @class = "editLink" })
上面链接的快照如下:

因此,可以在 `Global.asax` 中添加一个自定义的 maproute 规则,如下所示:
//..
 
routes.MapRoute(
    "AddressSave",
    "Address/Save/{addressNo}/{personNo}",
    new { controller = "Address", action = "Save", 
         addressNo = UrlParameter.Optional, personNo = UrlParameter.Optional }
);
 
//.. 
上述两种技术中的任何一种都可以使用。
16) 如何实现表格行的全选和全不选?
在许多应用程序中,有时需要一次性选中或取消选中表格中的所有复选框,如下所示:
可以使用以下脚本来实现这样的功能:
..
<br />
| <a href="#" class="checkALLRecords" id="checkALL">Check ALL</a> | <a href="#" class="unCheckALLRecords" id="unCheckALL">Uncheck ALL</a> |
<br />
..
<table id="NoteTable"></table>
..  
//..
 
        //check ALL records
        $("#checkALL").live("click", function (e) 
        {
                e.preventDefault();                                           
                CheckALL(true);
        });    
   
        //uncheck ALL records
        $("#unCheckALL").live("click", function (e) 
        {
                e.preventDefault();                                           
                CheckALL(false);
        });   
//..  
    function CheckALL(state)
    {
                            var rows = $("#NoteTable tr");
                                                       
                            for(var i=0; i< rows.length; i++)
                            {                               
                                var row = $(rows).eq(i);
                                                                                                                               
                                var span = row.find('span#cboxSpan');
                                var cb = row.find('span#cboxSpan').find('input.cboxDELclass');
                                
                                if (state==true)                                                                                                    
                                    cb.attr('checked',true);
                                else                                    
                                    cb.attr('checked',false);
                            }                           
    }
//..  
上述两种技术中的任何一种都可以使用。
17) 如何显示“正在加载数据”
在加载多行数据时,应向用户显示“正在加载数据”消息。

可以根据需要的消息自定义以下 div:
..
<div id="loadMessage"></div>
..   可以使用以下 JavaScript 函数来自定义 div 区域:..
function showLoader(root, txt) {
       
    $("#loadMessage").html("");
    $("#loadMessage").show();
    var loader = '<img src="' + root + '/ajax-loader.gif" align="absmiddle"> <span><br/>' + txt + '...</span>';
    $("#loadMessage").fadeIn(100).html(loader);
}
function hideLoader() {
    $("#loadMessage").hide();
}
..   上述两种技术中的任何一种都可以使用。
18) 如何使用 jQuery 创建主从表格(master-detail grids)?
点击主行时,详情行会显示在主表格下方,如下所示:
 

以下表格用作网格:
..
<table id="CountryTable" class="hovertable2"></table>
<br />
<br />
<table id="CityTable" class="hovertable"></table>
..    使用以下 JavaScript 函数模拟主从方法:..
 function setTableRowClick()
   {        
        $("#CountryTable tr  td.clickable").unbind('click');
        
        $('#CountryTable  tr  td.clickable').click(function ()         
        {           
             var row = $(this).parent();             
             setRow(row);
        });
        //-------------        
        
   }//func 
   function setRow(row)
   {   
              var rowid = row.attr('id'); //current
                            
              var higlightedCountryTableRowid = $("#pageinfo .higlightedCountryTableRowid").text();               
               $("#pageinfo .higlightedCountryTableRowid").html(rowid.toString());
              if ((rowid==0) || (rowid!=higlightedCountryTableRowid))
              {
                  //------
                    row.siblings().removeClass('diffColor');                                              
                    row.addClass("diffColor");
                  //-------
                 fillCityData(rowid);
             }
   }
..   
    function fillCountryData() 
    {                         
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetCountryList", "Country")",
                data: {},
                cache: false,
                dataType: "json",
                success: function (data) 
                {                                  
                    if (data.Html) 
                    {                                        
                        $("#CountryTable").html(data.Html); 
                        
                        buttonizeALL();
                        
                        setLinkAbilitesCountry();  
                        setLinkAbilitesCity();
                                              
                        setTableRowClick();
                    }
                    else 
                    {
                        alert('opps-- country list error!'); 
                    }
                },                
                error: function(exp)        
                {
                         alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
     
    }//func
    function fillCityData(parCountryNo) 
    {                         
            $.ajax({
                type: "POST",                
                url: "@Url.Action("GetCityList", "Country")",
                data: { countryNo: parCountryNo},                
                cache: false,
                dataType: "json",
                success: function (data) 
                {                                  
                    if (data.Html) 
                    {                                       
                        $("#CityTable").html(data.Html);        
                        
                        buttonizeALL();
                        setLinkAbilitesCity();                        
                        setTableRowClick();
                    }
                    else 
                    {
                        alert('opps-- city list error!'); 
                    }
                },                
                error: function(exp)        
                {
                         alert('Error address : ' + exp.responseText);
                }                
            }); //end ajax call
     
    }//func
.. 
 
结论  
希望本文能有所帮助。


