2019/0618/MVC Part2 PhotoSharing Route & Sitemap & _LayOut & AJAX
Last updated
Last updated
今日 倒數第二次 MVC課程
今日會把Part2 結束
兩個重點
一個是路由
預設長這樣
接著我們自己定義一個
沒放在大括弧 { } 就要完全一樣照打不會自動去找
有點類似 donaname
可以讓懂得人也看不出你網站結構
網址沒有再分大小寫
Constraints 約束 ( 正負向表列
Regular Expression
^開頭$結尾
[ ] 或
在 [ ] 內多一個^是負向表列
例如留言的url為留言的title
首先啟用自訂action 方法
再到controller 新增action 專門服務它
寫自訂
Find 只能找 key
所以要用where
如果title一樣怎辦 , 結果說機率太小所以沒處理
記得要啟用 [Route(@”photo/title/{title}”)]
SEO 排名會比較前面
以上為路游的介紹
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace PhotoSharing
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
///////////////////////////////
//5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
//啟用自訂Action當作路由方法
routes.MapMvcAttributeRoutes();
/////////////////////
routes.MapRoute(
name: "PhotoRoute",
url: "photos/{id}",
defaults: new { controller = "Photos", action = "Display" }
//constraints: new { id=@"^[1-3]$"}
);
/////////////////////////
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PhotoSharing.Models;
using PhotoSharing.DAL;
using System.Net;
namespace PhotoSharing.Controllers
{
public class PhotosController : Controller
{
//2.2建立Data Context 來自 Photo Model 的 PhotoSharingContext
PhotoSharingContext context = new PhotoSharingContext();
// GET: Photos
//2.3-1 Index()回傳Photo
public ActionResult Index()
{
ViewBag.Date = DateTime.Now; //用ViewBag帶入今日日期
return View(context.Photos.ToList());
}
//2.3-2 Display(int id) 透過id參數回傳Photo,若找不到回傳HttpNotFound()helper
public ActionResult Display(int? id)
{
ViewData["Date"] = DateTime.Now; //用ViewData帶入今日日期
if (id==null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Photo photo = context.Photos.Find(id);
if(photo==null)
{
return HttpNotFound("abcde");
}
return View("Display", photo);
}
//2.3-7 建立GetImage(int id)回傳File(photo.PhotoFile, photo.ImageMimeType)
//這不是View()Helper的ActionResult, 這是File()helper
public FileContentResult GetImage(int id)
{
Photo photo = context.Photos.Find(id);
return File(photo.PhotoFile, photo.ImageMimeType);
}
//2.3-3 GET:Create() 產生新增Photo作業,並回傳 new Photo()並產生CreatedDate屬性值= DateTime.Today
public ActionResult Create()
{
Photo newPhoto = new Photo();
newPhoto.CreatedDate = DateTime.Today;
return View("Create",newPhoto);
}
//2.3-4 Post:Create(Photo photo, HttpPostedFileBase image),使用HTTP POST,執行新增Photo回存作業,回傳RedirectToAction()helper
// 如果ModelState.IsValid==false,回傳Photo給View, 反之執行新增Photo回存作業
// photo.ImageMimeType = image.ContentType;
// photo.PhotoFile = new byte[image.ContentLength];
// image.InputStream.Read(photo.PhotoFile, 0, image.ContentLength);
[HttpPost,ValidateAntiForgeryToken]
public ActionResult Create(Photo photo,HttpPostedFileBase image)
{
photo.CreatedDate = DateTime.Today;
if(ModelState.IsValid)
{
//有post照片才做照片上傳的處理
if (image!=null)
{
photo.ImageMimeType = image.ContentType; //抓照片型態
photo.PhotoFile = new byte[image.ContentLength]; //取得上傳照片的大小再轉byte陣列
image.InputStream.Read(photo.PhotoFile, 0, image.ContentLength);
}
context.Photos.Add(photo);
context.SaveChanges();
return RedirectToAction("Index");
}
else
{
return View("Create", photo);
}
}
//2.3-5 Get:Delete(int id)產生刪除Photo作業,並回傳Photo(),若找不到回傳HttpNotFound()helper
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Photo photo = context.Photos.Find(id);
if (photo == null)
{
return HttpNotFound();
}
return View("Delete", photo);
}
//2.3-6 Post:建立DeleteConfirmed(int id)使用[ActionName("Delete")]屬性,透過HTTP POST,執行刪除Photo回存作業.回傳RedirectToAction()helper
[HttpPost,ValidateAntiForgeryToken]
[ActionName("Delete")]
public ActionResult DeleteConfirmed(int? id)
{
Photo photo = context.Photos.Find(id);
context.Photos.Remove(photo);
context.SaveChanges();
return RedirectToAction("Index");
}
//3.13-3 在PhotoController中的_PhotoGallery Action上標註排除使用Filter
[ValueReporter(IsCheck=false)]
//3.6.在PhotoController.cs建立[ChildActionOnly] _PhotoGallery action,用於Partial View
public ActionResult _PhotoGallery(int number=0)
{
List<Photo> photos;
if (number == 0)
{
//Lambda
photos = context.Photos.OrderByDescending(p => p.CreatedDate).ThenBy(p => p.PhotoID).ToList();
//LINQ
//photos = (from p in context.Photos
// orderby p.CreatedDate descending, p.PhotoID ascending
// select p).ToList();
//SQL
//Select * from photo
//order by CreatedDate desc,p.PhotoID
}
else
{
photos = context.Photos.OrderByDescending(p => p.CreatedDate).ThenBy(p => p.PhotoID).Take(number).ToList();
//LINQ
//photos = (from p in context.Photos
// orderby p.CreatedDate descending, p.PhotoID ascending
// select p).Take(number).ToList();
//SQL
//Select top 2 * from photo
//order by CreatedDate desc,p.PhotoID
}
return PartialView("_PhotoGallery", photos);
}
//4.1建立ExceptionDemo Action引發錯誤
//[HandleError(View="ExceptionError")]
public ActionResult ExceptionDemo()
{
int i = 0;
int j = 10 / i;
return View();
}
//4.5建立SlideShow Action並自訂NotImplementedException錯誤
[HandleError(View="ExceptionError")]
public ActionResult SliderShow()
{
throw new NotImplementedException("這一個SliderShow的功能還沒有做好哦!!!");
}
//5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
[Route(@"photo/title/{title}")]
public ActionResult DisplayByTitle(string title)
{
if (title == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Photo photo = context.Photos.Where(p=>p.Title==title).FirstOrDefault();
if(photo==null)
{
return HttpNotFound("abcde");
}
return View("Display", photo);
}
}
}
//5.1 設定自訂路由
//5.1-1 在\App_Start\RouteConfig.cs自訂photo路由PhotoRoute
//5.1-1.1 測試
//5.1-1.2 測試後加上下段,將constraints限制存取的id導到錯誤處理頁面
//<customErrors mode = "On" >
// < error statusCode="404" redirect="/404.html" />
//</customErrors>
//5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
//5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
//5.1-3.1 測試
//5.1-4 在_PhtotGallery PartialView加上@Html.ActionLink("詳細資料byTitle", "DisplayByTitle", new { Title = item.Title })
//5.1-4.1 測試
//5.2 加入Navigation
//5.2.1 NuGet下載MvcSiteMapProvider.MVC5
// ********需先把EntityFramework降版至6.1.3再安裝MvcSiteMapProvider.MVC5,裝完後根目錄下會有sitemap檔
//5.2-2 自訂mvcSiteMapNode(Mvc.sitemap檔)
//5.2-3 顯示Menu及SiteMapPath(Photo\Index.cshtml)
下個例子要講layout
Navbar
有很多個做法 老師介紹他覺得還不錯的
Sitemap 在 webform 有控制項
但在mvc首先要安裝插鍵
但要先把entityframework 降版 6.1.3
寫mvc要知道有些功能通常都有元件
Mvc sitemap provider 可以只裝mvc5的版本
把它當像是webform裡面的sitemap來用就好
一個xml檔案
接著做個簡單的例子
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="All Photos" controller="Photos" action="Index"/>
<mvcSiteMapNode title="Create Photos" controller="Photos" action="Create"/>
<mvcSiteMapNode title="ExceptionDemo" controller="Photos" action="ExceptionDemo"/>
<mvcSiteMapNode title="SliderShow" controller="Photos" action="SliderShow"/>
</mvcSiteMapNode>
</mvcSiteMap>
有層級關係
指定controllername跟actionname
這個講完後會補充 error hander 時提到的slider showS
做好後
現在先讀出來
到 views -> photos -> index.cshtml
@Html.mvcsitemap().menu()
@Html.mvcsitemap().sitemappath()
有bug 沒解決 下課休息
剛剛的問題是發生在Routerconfig 錯了
400 request 就錯了
直接打/photos不帶任何參數就可以
url沒有分大小寫
所以要自訂自己的router 千萬不要跟 controllername一樣不然就沒意義
等等在 layout 解決
Navbar 其實就是用 ul 實現的所以現在就先用 ul 做
@Menu 後面的參數 多載很多 必須要知道到底在調整啥
現在先以 (三參數做示範
開始節點
子節點
階層調整成需求的 就可以上 class
這個sitemap先壓縮起來這其實只是鋪耿要給layout用的
下午例子要去layout跟menu一起講
下午還要講 ajax ??
@{
ViewBag.Title = "討論區";
}
<div>
選單:@Html.MvcSiteMap().Menu(false,false,false)
目前所在位置:@Html.MvcSiteMap().SiteMapPath()
<h2>討論區</h2>
<hr />
<p>@Html.ActionLink("新增留言", "Create")</p>
@Html.Action("_PhotoGallery", "Photos")
</div>
//5.1 設定自訂路由
//5.1-1 在\App_Start\RouteConfig.cs自訂photo路由PhotoRoute
//5.1-1.1 測試
//5.1-1.2 測試後加上下段,將constraints限制存取的id導到錯誤處理頁面
//<customErrors mode = "On" >
// < error statusCode="404" redirect="/404.html" />
//</customErrors>
//5.1-2 建立自訂路由的ACTION:DisplayByTitle(PhotoController.cs)
//5.1-3 在\App_Start\RouteConfig.cs啟用自訂ACTION 路由==> routes.MapMvcAttributeRoutes();
//5.1-3.1 測試
//5.1-4 在_PhtotGallery PartialView加上@Html.ActionLink("詳細資料byTitle", "DisplayByTitle", new { Title = item.Title })
//5.1-4.1 測試
//5.2 加入Navigation
//5.2.1 NuGet下載MvcSiteMapProvider.MVC5
// ********需先把EntityFramework降版至6.1.3再安裝MvcSiteMapProvider.MVC5,裝完後根目錄下會有sitemap檔
//5.2-2 自訂mvcSiteMapNode(Mvc.sitemap檔)
//5.2-3 顯示Menu及SiteMapPath(Photo\Index.cshtml)
Layout 相當於 webform 的 masterpage
Shared 是大家都要用到的東西就會放在這
Partialview
錯誤頁面 等等 …
_有底線的沒辦法直接存取
所有的 View都在 @RenderBody() 裡面
接著真正的做一個空的 _layout
ViewBag.Title 通常表示那個 view 的資訊
Bundle 在講 ??
@styles.Render
用html5語意標籤來寫可以增加 seo 排名
接著調整樣式 利用 bs 3
重點來了
要把 @Html.ActionLink 改為 @sitemap
這時候問題來了 ul 如果用 sitemap 並沒辦法套用 class
那就要用 jq dom 塞 … ( 如果不是預設的內容就要用 jq 塞
接著測試 新增 TestBoostrap.cshtml
@{Layout=”_MainLayout.cshtml”}
各自view所做的樣式修改
最好是留在各自的view內
然後利用@section CSS{<style></style>}
到原本的layout內利用
@RenderSection(“CSS”,false)
@RenderSection(“Script”,false)
false不需要每一個view都有那個區塊
@{
//Layout = "~/Views/Shared/_Layout.cshtml";
Layout = "~/Views/Shared/_MainLayout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
@*//6.1-1-1<title>@ViewBag.Title</title>*@
<title>@ViewBag.Title | 高屏澎東分署股份有限公司</title>
@*//6.1-1-1<title>@ViewBag.Title</title>*@
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
@*6.2.4 將自訂CSS Section插入Layout*@
<link href="~/Content/Site.css" rel="stylesheet" />
@RenderSection("CSS", false)
</head>
<body>
@*//6.1-1-2 製作<header> </header>裡的Navbar*@
<header>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#" class="navbar-brand">WDA</a>
@*@Html.ActionLink("應用程式名稱", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })*@
</div>
<div class="navbar-collapse collapse">
@*<ul class="nav navbar-nav">
<li>@Html.ActionLink("首頁", "Index", "Home")</li>
<li>@Html.ActionLink("關於", "About", "Home")</li>
<li>@Html.ActionLink("連絡人", "Contact", "Home")</li>
<li>@Html.ActionLink("討論區", "Index", "Photos")</li>
</ul>*@
@Html.MvcSiteMap().Menu()
</div>
</div>
</div>
</header>
@*6.1-1-3...........................................*@
<section class="container body-content">
@RenderBody()
</section>
@*6.1-1-4............................................*@
<footer class="container">
<hr />
<p>目前所在位置:@Html.MvcSiteMap().SiteMapPath()</p>
<p>© @DateTime.Now.Year - 高屏澎東分署股份有限公司</p>
</footer>
@*6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS*@
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
@*6.2.5 將自訂Scripts Section插入Layout*@
@*//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>*@
@RenderSection("Script", false)
<script>
//6.5.2 更新(Shared\_MainLayout.cshtml), 加入JQUERY, 產生 < ul id = "menu" class="nav navbar-nav" >
$('#menu').addClass('nav navbar-nav');
$('#menu').append('<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>');
</script>
</body>
</html>
//6.1 建立layout
//6.1-1 建立layout View(Shared\_MainLayout.cshtml)
// Templete:empty(without model)
// 不要勾選Use a Layout Page
// 修改內容(可參考_Layout.cshtml)
//6.1-1-1 <title>@ViewBag.Title</title>
//6.1-1-2 製作<header> </header>裡的Navbar
//6.1-1-3 <section>@RenderBody()</section>
//6.1-1-4 <footer>@Html.MvcSiteMap().SiteMapPath()</footer>
//6.1-2 (_ViewStart.cshtml)設定預設的Layout
//6.1-3 註解(photo/index.cshtml)原本 5.2-3的Menu及SiteMapPath
//6.2.1 *Manage NuGet Package 加入BootStrap & Jquery(已存在則省略)
//6.2.2 在layout View(Shared\_MainLayout.cshtml)使用BootStrap CSS
// 在<Head>標籤內加入
// 1.<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
//6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS
// 在</Body>標籤前加入
// 1.<script src="~/Scripts/jquery-3.1.1.min.js"></script>
// 2.<script src="~/Scripts/bootstrap.min.js"></script>
//6.2.4 將自訂css Section插入Layout(Shared\_MainLayout.cshtml)
// 在<Head>標籤內加入(6.2.2的後面)
// @RenderSection("CSS", false)
//6.2.5 將自訂Scripts Section插入Layout(Shared\_MainLayout.cshtml)
// 在</body>標籤上一行加入
// @RenderSection("Scripts", false)
//6.3-1 加入TestBootStrap Action
//6.3.2 在Photos裡建立Bootstrap View:TestBootStrap.cshtml,使用Bootstrap Grid System
// Template:Empty (without model)
// 勾選Use a Layout Page
// 選擇_MainLayout.cshtml為主版
// 修改內容
//6.3.3 在TestBootStrap.cshtml View中定義Section
// @section CSS{.......}
//6.4.1 更新Create View,使用Bootstrap Form/Button
//6.4.2 更新Create View,自訂SCRIPT,使用@section
// @section Scripts{.......}
//6.5.1 更新(Shared\_MainLayout.cshtml),SiteMap使用Bootstrap Navbar
//6.5.2 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<ul id="menu" class="nav navbar-nav">
//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>
AJAX即“Asynchronous JavaScript and XML”(非同步的JavaScript與XML技術),指的是一套综合了多項技術的瀏覽器端網頁開發技術。
一個crud 通常就是一個 controller
那我們就新增一個 commentController
該using的 + dbcontext
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PhotoSharing.DAL;
using PhotoSharing.Models;
namespace PhotoSharing.Controllers
{
public class CommentController : Controller
{
//7.2-1 宣告PhotoSharingContext()並在建構式建構DBContext物件
PhotoSharingContext context = new PhotoSharingContext();
//7.2-2 加入_CommentsForPhoto Action
[ChildActionOnly]//無法在瀏覽器上用URL存取此action
public ActionResult _CommentsForPhoto(int PhotoID)
{
var comments = from c in context.Comments
where c.PhotoID == PhotoID
select c;
//為了在View裡取得PhotoID的值所以先存在ViewBag裡
ViewBag.PhotoID = PhotoID;
return PartialView(comments.ToList());
}
//7.5-1 加入_Create Action
public ActionResult _Create(int PhotoID)
{
Comment newComment = new Comment();
newComment.PhotoID = PhotoID;
ViewBag.PhotoID = PhotoID;
return PartialView("_CreateAComment");
}
//7.6-1 在CommentController加入_CommentsForPhoto POST Action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult _CommentsForPhoto(Comment comment, int PhotoID)
{
context.Comments.Add(comment);
context.SaveChanges();
var comments = from c in context.Comments
where c.PhotoID == PhotoID
select c;
//7.6-1 在CommentController加入_CommentsForPhoto POST Action(第二個畫面)
ViewBag.PhotoID = PhotoID;
return PartialView("_CommentsForPhoto", comments.ToList());
}
//7.8-1加入CommentControl的Delete ACTION
public ActionResult Delete(int id)
{
Comment comment = context.Comments.Find(id);
context.Comments.Remove(comment);
context.SaveChanges();
return RedirectToAction("Display","Photos",new { id=comment.PhotoID});
}
}
}
增加一個 partialview
在上面加上 [childactiononly]
不直接回應瀏覽器要求
如果直接在url key 會顯示此動作只能由子要求存取
查詢帶參數到partialview
這樣 這個 partialview 就做好了
接著新增partialview的檢視 create as a partialview
@model IEnumerable<PhotoSharing.Models.Comment>
@using (Ajax.BeginForm("_CommentsForPhoto",new { PhotoID=ViewBag.PhotoID},new AjaxOptions {UpdateTargetId= "comments-tool",HttpMethod="Post" }))
{
<div id="comments-tool">
<div class="well">
@* 7.6-4 加入_Create Action********************************************** *@
@*Action Name是_Create才對!!*@
@Html.Action("_Create", "Comment", new { PhotoID = ViewBag.PhotoID })
@foreach (var item in Model)
{
@*7.3 在/Shared/_CommentsForPhoto.cshtml加入IEnumerable<T>及foreach (var item in Model){}*@
<div class="panel panel-warning">
<div class="panel-heading">
<h4>@item.Subject</h4>
</div>
<div class="panel-body">
<p>@item.Body</p>
<p class="text-right">
回覆人:@item.UserName
</p>
</div>
@*//7-8-2 在_CommentsForPhoto.cshtml加入Delete連結*@
<div class="panel-footer">
@Html.ActionLink("刪除回覆","Delete",new { id=item.CommentID},new { @class="btn btn-danger", onclick="return confirm('確定刪除嗎??')"})
</div>
</div>
}
</div>
</div>
}
用 foreach 讀出來
接著去修改 Display.cshtml的 partialview鏈結
以上為顯示的部分
修改這些是為了 等等 的 ajax
Microsoft.jquery.unobtrusive.ajax
這個是用後端然後可以寫前端的套件
Include script jquery.unobtrusive-ajax.js
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
@*//6.1-1-1<title>@ViewBag.Title</title>*@
<title>@ViewBag.Title | 高屏澎東分署股份有限公司</title>
@*//6.1-1-1<title>@ViewBag.Title</title>*@
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
@*6.2.4 將自訂CSS Section插入Layout*@
<link href="~/Content/Site.css" rel="stylesheet" />
@RenderSection("CSS", false)
</head>
<body>
@*//6.1-1-2 製作<header> </header>裡的Navbar*@
<header>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="#" class="navbar-brand">WDA</a>
@*@Html.ActionLink("應用程式名稱", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })*@
</div>
<div class="navbar-collapse collapse">
@*<ul class="nav navbar-nav">
<li>@Html.ActionLink("首頁", "Index", "Home")</li>
<li>@Html.ActionLink("關於", "About", "Home")</li>
<li>@Html.ActionLink("連絡人", "Contact", "Home")</li>
<li>@Html.ActionLink("討論區", "Index", "Photos")</li>
</ul>*@
@Html.MvcSiteMap().Menu()
</div>
</div>
</div>
</header>
@*6.1-1-3...........................................*@
<section class="container body-content">
@RenderBody()
</section>
@*6.1-1-4............................................*@
<footer class="container">
<hr />
<p>目前所在位置:@Html.MvcSiteMap().SiteMapPath()</p>
<p>© @DateTime.Now.Year - 高屏澎東分署股份有限公司</p>
</footer>
@*6.2.3 在layout View(Shared\_MainLayout.cshtml)使用BootStrap/Jquery JS*@
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
@*6.2.5 將自訂Scripts Section插入Layout*@
@*//6.5.3 更新(Shared\_MainLayout.cshtml),加入JQUERY, 產生<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>*@
@RenderSection("Script", false)
<script>
//6.5.2 更新(Shared\_MainLayout.cshtml), 加入JQUERY, 產生 < ul id = "menu" class="nav navbar-nav" >
$('#menu').addClass('nav navbar-nav');
$('#menu').append('<li><form method="get" action="https://www.google.com.tw/search" class="form-inline"><input id="q" name="q" type="text" class="form-control" placeholder="Please Input Something..." /><input id="Submit1" type="submit" value="Search" class="btn btn-success" /></form></li>');
</script>
</body>
</html>
接著回到 commentcontroller.cs
新增一個 _Create的partialview
一樣查詢
為了區別viewname可以跟action不同名稱
Return 時 雙引號 “partialview名稱”
接著新增檢視 記得要把VIEW名稱改為“partialview名稱”
接著到 shared _createacomment.cshtml (要做表單 ?
display
_commentsForPhoto.cshtml
_createacomment.cshtml (後悔了 改為範本 讓它直接蓋過去
@model PhotoSharing.Models.Comment
@Html.AntiForgeryToken()
@*7.6-2 _CreateAComment.cshtml加入Html Helper 及 class屬性*@
<div class="form-horizontal">
<h4>Comment</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Subject, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Subject, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Subject, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Body, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Body, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Body, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
要幫整個_commentsForPhoto.cshtml 套上form
而且要用 ajax的方法
@using (Ajax.BeginForm(“_createacomment.cshtml”,new{PhotoID=}, AjaxOptions局部區塊ID…)
AjaxOptions {UpdateTargetId=局部區塊ID,送出去的方法}
再回到 CommentController.cs 新增 [HttpPost]_CommentsForPhoto 多載(不同參數不同傳送方法)
把資料讀出來在塞回 同一頁 自己
@using (Ajax.BeginForm("_CommentsForPhoto",new { PhotoID=ViewBag.PhotoID},new AjaxOptions {UpdateTargetId= "comments-tool",HttpMethod="Post" }))
{Formcontent}
測試
剛剛用範本產生的部分有錯 削掉就成功了
//7 用ajax的方式來實現回覆留言的功能
//7.1 加入CommentController(Mvc5 Controller-Empty)
// 在CommentController加入_Create Action
// 在_CreateAComment View使用AJAX
//7.2 加入CommentController(Mvc5 Controller-Empty)
//7.2-1 宣告PhotoSharingContext()並在建構式建構DBContext物件
//7.2-2 加入_CommentsForPhoto Action
//7.2-3 加入_CommentsForPhoto Action的Partial View
// 使用Scaffold template:Empty
// Model Class:Comment (PhotoSharing.Models)
// Data Context Class:PhotoSharingContext (PhotoSharing.DAL)
// 勾選Create as a partial view核取方塊
//7.2-4 將_CommentsForPhoto.cshtml移至Shared目錄
//
//7.3 在/Shared/_CommentsForPhoto.cshtml加入IEnumerable<T>及foreach (var item in Model){}
//7.4 在/Photo/Display View加入@Html.Action("_CommentsForPhoto", "Comment", new { PhotoID = Model.PhotoID })
//可先測試一下在Display中是否能正常顯示回覆留言的PartialView
// 使用NuGet安裝套件
// 1.*Jquery(如果需要)
// 2.Microsoft.jQuery.Unobtrusive.Ajax
//7.5-1 加入_Create Action
//7.5-2 加入_Create Action的_CreateAComment View
// 使用Scaffold template:Empty
// Model Class:Comment (PhotoSharing.Models)
// Data Context Class:PhotoSharingContext (PhotoSharing.DAL)
// 勾選Create as a partial view核取方塊
//7.5-3 將_CreateAComment.cshtml移至Shared目錄
// GET: /Comment/_Create. A Partial View for displaying the create comment tool as a AJAX partial page update
//7.6-1 在CommentController加入_CommentsForPhoto POST Action
//7.6-2 /Shared/_CreateAComment.cshtml加入Html Helper 及 class屬性
//7.6-3 /Shared/_CommentsForPhoto.cshtml使用Ajax.BeginForm
//7.6-4 /Shared/_CommentsForPhoto.cshtml加入@Html.Action("_Create", "Comment", new { PhotoID = ViewBag.PhotoId })
// 透過@Html.Action加入_CreateAComment Partial View
//7.7 在_MainLayout.cshtml加入SCRIPT
//7.7-1 加入*jquery-3.1.1.min.js(如果需要的話)(注意:不可用jquery-1.XXX版本)
//7.7-2 *****加入jquery.unobtrusive-ajax.min.js*****這個一定要記得安裝啊!!!!!!
//到這裡可以先測試一下在Display中是否能以Ajax方式新增留言
//7.8 加入CommentControl的Delete ACTION
//7.8-1加入CommentControl的Delete ACTION
//7-8-2 在_CommentsForPhoto.cshtml加入Delete連結
//7-9 測試:http://localhost:3395/Photo/Display/1
結果ajax的地方沒有錄影錄到 …
Panel-footer
有登入還可以判斷登入狀態
下一個 actionlink
要帶參數 然後 帶 class 帶 onclick
接著到 controller 寫刪除的 action
到此 MVC Part2告一個段落 , 可以拿它來應用很多地方
接下來會介紹一些跟專案本身進度沒關聯性
如 Include bundle ?
狀態管理 viewbag viewdata session