2019/0618/MVC Part2 PhotoSharing Route & Sitemap & _LayOut & AJAX

今日 倒數第二次 MVC課程

今日會把Part2 結束

#09_Route_Sitemap ( Route )

兩個重點

一個是路由

預設長這樣

接著我們自己定義一個

沒放在大括弧 { } 就要完全一樣照打不會自動去找

有點類似 donaname

可以讓懂得人也看不出你網站結構

網址沒有再分大小寫

Constraints 約束 ( 正負向表列

##Expration expression

Regular Expression

^開頭$結尾

[ ] 或

在 [ ] 內多一個^是負向表列

##接著要把url改為自訂的相對應內容

例如留言的url為留言的title

首先啟用自訂action 方法

再到controller 新增action 專門服務它

寫自訂

Find 只能找 key

所以要用where

如果title一樣怎辦 , 結果說機率太小所以沒處理

記得要啟用 [Route(@”photo/title/{title}”)]

###Chrome 如果 url 有特殊符號 就是被編碼掉了 如空白就是%

SEO 排名會比較前面

以上為路游的介紹

###App_Start/RouteConfig.cs

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 }
            );
        }
    }
}

###Controller s/PhotosController.cs

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)

#09_Route_Sitemap ( Sitemap )

下個例子要講layout

Navbar

有很多個做法 老師介紹他覺得還不錯的

Sitemap 在 webform 有控制項

但在mvc首先要安裝插鍵

但要先把entityframework 降版 6.1.3

寫mvc要知道有些功能通常都有元件

Mvc sitemap provider 可以只裝mvc5的版本

把它當像是webform裡面的sitemap來用就好

一個xml檔案

接著做個簡單的例子

###Mvc.sitemap

<?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 ??

###Mvc.sitemap

###Views/photos/index.cshtml


@{
    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

#10_LayOut

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/_ViewStart.cshtml

@{
    //Layout = "~/Views/Shared/_Layout.cshtml";
    Layout = "~/Views/Shared/_MainLayout.cshtml";
}

###View/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>&copy; @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>

#11AJAX

如果沒有像Webform AJAX控制項時的用法

AJAX即“Asynchronous JavaScript and XML”(非同步的JavaScript與XML技術),指的是一套综合了多項技術的瀏覽器端網頁開發技術。

一個crud 通常就是一個 controller

那我們就新增一個 commentController

該using的 + dbcontext

###Controller s/commentController .cs

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

###Views/Shared/_CommentsForPhoto.cshtml

@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

##接著要安裝Ajax的插件

Microsoft.jquery.unobtrusive.ajax

這個是用後端然後可以寫前端的套件

Include script jquery.unobtrusive-ajax.js

###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>&copy; @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 (要做表單 ?

Partialview 階層

display

_commentsForPhoto.cshtml

_createacomment.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

Last updated

Was this helpful?