《ProASP.NETMVC5》、《锋利的jQuery》
此系列皆使用VS2017+C#作为开发环境。如果有什么问题或者意见欢迎在留言区进行留言。
本章内容:分页、自定义HtmlHelper、通过模态窗口确认是否提交表单、上传文件、获取文件、预览文件、select元素、表单提交数组、checkbox、js确认关闭页面
注:在对EF中的数据进行更改时,需要调用对应Context的SaveChange方法才能对更改进行保存。
一、视图分页视图模型
首先创建一个视图模型用于确定每页的书籍数、页数
1publicclassPagingInfo2{3publicintTotalItems{get;set;}4publicintItemsPerPage{get;set;}5publicintCurrentPage{get;set;}67publicintTotalPages8{9get=>(int)Math.Ceiling((decimal)TotalItems/ItemsPerPage);10}11}
然后创建另一个视图模型用于确定该分页信息以及各分页的书籍:
1publicclassBookListViewModel2{3publicIEnumerableBookDetails{get;set;}4publicPagingInfoPagingInfo{get;set;}5}
创建一个自定义HtmlHelper用于在视图中使用Razor语法获取分页,在ASP.NETCore中TagBuilder继承自IHtmlContent,不能直接对TagBuilder进行赋值,需调用MergeAttribute方法和InnerHtml属性的AppendHtml方法编写标签;并且TagBuilder没有实现ToString方法,只能通过其WriteTo方法将内容写到一个TextWriter对象中以取出其值:
二、编辑图书信息页面的首页
在此准备使用Session更快地获取图书信息,为了在使用时更直观,此处对Session类进行扩展:
1publicstaticclassSessionExtensions2{3publicstaticvoidSet(thisISessionsession,stringkey,Tvalue)4{5session.SetString(key,JsonConvert.SerializeObject(value));6}78publicstaticTGet(thisISessionsession,stringkey)9{10varvalue=session.GetString(key);11returnvalue==nulldefault(T):JsonConvert.DeserializeObject(value);12}13}
创建一个BookInfo控制器:
1publicclassBookInfoController:Controller2{3privateLendingInfoDbContext_lendingInfoDbContext;45publicBookInfoController(LendingInfoDbContextcontext)6{7_lendingInfoDbContext=context;8}9}
创建学生浏览的首页:
在此使用Session获取书籍列表:
创建BookInfo控制器并确定其中每个分页的书籍数,使用Session获取更快地获取书籍信息:
1publicclassBookInfoController:Controller2{3privateLendingInfoDbContext_context;4privatestaticintamout=4;56publicBookInfoController(LendingInfoDbContextcontext)7{8_context=context;9}1011publicIActionResultIndex(stringcategory,intpage=1)12{13IEnumerablebooks=null;14if(HttpContext.Session!=null)15{16books=HttpContext.Session.Get>("bookDetails");17}18if(books==null)19{20books=_context.BooksDetail;21HttpContext.Session.Set>("books",books);22}23BookListViewModelmodel=newBookListViewModel()24{25PagingInfo=newPagingInfo()26{27ItemsPerPage=amout,28TotalItems=books.Count(),29CurrentPage=page,30},31BookDetails=books.OrderBy(b=>b.FetchBookNumber).Skip((page-1)*amout).Take(amout)32};33returnView(model);34}3536publicFileContentResultGetImage(stringisbn)37{38BookDetailstarget=_context.BooksDetail.FirstOrDefault(b=>b.ISBN==isbn);39if(target!=null)40{41returnFile(target.ImageData,target.ImageMimeType);42}43returnnull;44}45}
视图页面:
33行利用BookListViewModel中PagingInfo的CurrentPage获取各序号,32行中使img元素的src指向BookInfoController的GetImage方法以获取图片:
在此同样使用Session获取书籍列表:
利用[Authorize]特性指定Role属性确保只有Admin身份的人才能访问该页面:
1[Authorize(Roles="Admin")]2publicIActionResultBookDetails(stringisbn,intpage=1)3{4IEnumerablebooks=null;5BookListViewModelmodel;6if(HttpContext.Session!=null)7{8books=HttpContext.Session.Get>("bookDetails");9}10if(books==null)11{12books=_context.BooksDetail.AsNoTracking();13HttpContext.Session.Set>("books",books);1415}16if(isbn!=null)17{18model=newBookListViewModel()19{20BookDetails=newList(){books.FirstOrDefault(b=>b.ISBN==isbn)},21PagingInfo=newPagingInfo()22};23returnView(model);24}25model=newBookListViewModel()26{2728PagingInfo=newPagingInfo()29{30ItemsPerPage=amout,31TotalItems=books.Count(),32CurrentPage=page,33},34BookDetails=books.OrderBy(b=>b.FetchBookNumber).Skip((page-1)*amout).Take(amout)35};36returnView(model);37}
BookDetails视图,confirmDelete为删除按钮添加了确认的模态窗口;
53行为glyphicon为Bootstrap提供的免费图标,只能通过span元素使用:
Index页面:
BookDetails页面:
三、添加书籍信息
在此为了接受图片需要使用IFormFile接口,为了使图片以原有的格式在浏览器中显示,需要用另一个字段ImageType保存文件的格式;
39页使用TempData传递一次性信息告知书籍添加成功,在传递完成后TempData将被立即释放:
指定input的name属性为image以在上传表单时进行模型绑定,指定其accept属性令其打开文件选择框时只接收图片。
JS代码为input添加onchange事件以预览上传的图片,并为关闭或刷新页面时添加模态窗口进行确认,同时为提交按钮添加事件以重置window.onbeforeunload事件从而不弹出确认窗口:
四、删除书籍信息
删除书籍的动作方法:
此处通过在之前的BookDetails视图中指定input元素的type为checkbox,指定name为isbns以实现多个字符串的模型绑定:
1[Authorize(Roles="Admin")]2[HttpPost]3[ValidateAntiForgeryToken]4publicasyncTaskRemoveBooksAndBookDetails(IEnumerableisbns)5{6StringBuildersb=newStringBuilder();7foreach(varisbninisbns)8{9BookDetailsbookDetails=_lendingInfoDbContext.BooksDetail.First(b=>b.ISBN==isbn);10IQueryablebooks=_lendingInfoDbContext.Books.Where(b=>b.ISBN==isbn);11_lendingInfoDbContext.BooksDetail.Remove(bookDetails);12_lendingInfoDbContext.Books.RemoveRange(books);13sb.Append("《"+bookDetails.Name+"》");14await_lendingInfoDbContext.SaveChangesAsync();15}16TempData["message"]=$"已移除书籍{sb.ToString()}";17returnRedirectToAction("BookDetails");18}结果:
五、编辑书籍信息
动作方法:
此处视图与之前AddBookDetails大致相同,但在此对一些视图中的ISBN字段添加了readonly属性使它们不能被直接编辑:
结果:
六、查询特定书籍
1publicasyncTaskSearch(stringkeyWord,stringvalue)2{3BookDetailsbookDetails=newBookDetails();4switch(keyWord)5{6case"Name":7bookDetails=await_context.BooksDetail.FirstOrDefaultAsync(b=>b.Name==value);8break;9case"ISBN":10bookDetails=await_context.BooksDetail.FirstOrDefaultAsync(b=>b.ISBN==value);11break;12case"FetchBookNumber":13bookDetails=await_context.BooksDetail.FirstOrDefaultAsync(b=>b.FetchBookNumber==value);14break;15}1617if(bookDetails!=null)18{19returnRedirectToAction("EditBookDetails",new{isbn=bookDetails.ISBN});20}2122TempData["message"]="找不到该书籍";23returnRedirectToAction("BookDetails");24}