2014年6月23日 星期一

ASP.NET MVC 5 with CheckboxList 應用範例

前一陣子完成了「ASP.NET MVC - CheckBoxList 與 ValidationMessage (ASP.NET MVC 5 with Bootstrap3)」與「ASP.NET MVC - CheckBoxList 與 ValidationMessage (ASP.NET MVC 4 without Bootstrap)」這兩篇有關於 CheckBoxList 與 ASP.NET MVC ValidationMessage 的應用,但這兩篇文章與之前有關 CheckBoxList 的文章都只有展示 CheckBoxList 的功能,並沒有實際針對在資料的 CRUD(Create, Read, Update, Delete)操作上去怎麼使用,所以這一篇文章就來說明怎麼在資料的 CRUD 操作去使用 CheckBoxList。

 


開發環境:Visual Studio 2013 Update 2 , LocalDB , ASP.NET MVC 5 , Entity Framework 6.1.0

 

建立一個 ASP.NET MVC 5 專案

image

 

Foobar

這是我們要進行 CRUD 處理的 Table,而其中 Categories 欄位所要儲存的是 Northwind 的 Category 的 ID 編號,多個 Category ID 將會用「,」逗號分隔,

image

 

ViewModel

這邊建立 View 與 Controller 所使用的 ViewModel 類別,將原本 EF 所建立 Foobar 類別再另外建立 Partial Class 以及 MetadataType Class,

image

using System;
using System.ComponentModel.DataAnnotations;
 
namespace WebApplication1.Models
{
    [MetadataType(typeof(FoobarMetadata))]
    public partial class Foobar
    {
        public class FoobarMetadata
        {
            [Display(Name = "編號")]
            [Required(ErrorMessage = "為必要欄位")]
            public Guid ID { get; set; }
 
            [Display(Name = "名稱")]
            [Required]
            [StringLength(100, ErrorMessage = "請輸入名稱")]
            public string Name { get; set; }
 
            [Display(Name = "分類")]
            [Required(ErrorMessage = "請至少選擇一個分類")]
            public string Categories { get; set; }
 
            [Display(Name = "建立日期")]
            [Required(ErrorMessage = "為必要欄位")]
            public DateTime CreateDate { get; set; }
 
            [Display(Name = "更新日期")]
            [Required(ErrorMessage = "為必要欄位")]
            public DateTime UpdateDate { get; set; }
 
        }
 
        public string SelectedCategories { get; set; }
 
    }
}

 

Service

再來建立 FoobarService,

image

using System;
using System.Linq;
using WebApplication1.Infrastructure.Repository;
using WebApplication1.Models;
 
namespace WebApplication1.Infrastructure.Services
{
    public class FoobarService
    {
        private IRepository<Foobar> _Repository = new DataRepository<Foobar>();
 
        public void Create(Foobar instance)
        {
            if(instance == null)
            {
                throw new ArgumentNullException("instance", "null");
            }
            instance.ID = Guid.NewGuid();
            instance.CreateDate = DateTime.Now;
            instance.UpdateDate = DateTime.Now;
 
            this._Repository.Add(instance);
            this._Repository.SaveChanges();
        }
 
        public void Delete(Guid id)
        {
            var instance = this.GetOne(id);
            if (instance == null)
            {
                throw new InvalidOperationException("not found");
            }
 
            this._Repository.Delete(instance);
            this._Repository.SaveChanges();
        }
 
        public void Update(Foobar instance)
        {
            if (instance == null)
            {
                throw new ArgumentNullException("instance", "null");
            }
 
            instance.UpdateDate = DateTime.Now;
 
            this._Repository.Update(instance);
            this._Repository.SaveChanges();
        }
 
        public bool IsExists(Guid id)
        {
            return this._Repository.IsExists(x => x.ID == id);
        }
 
        public Foobar GetOne(Guid id)
        {
            return this._Repository.FirstOrDefault(x => x.ID == id);
        }
 
        public IQueryable<Foobar> GetAll()
        {
            return this._Repository.FindAll().OrderByDescending(x => x.CreateDate);
        }
 
 
    }
}

 

FoobarController

image

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using WebApplication1.Infrastructure.Services;
using WebApplication1.Models;
 
namespace WebApplication1.Controllers
{
    public class FoobarsController : Controller
    {
        private FoobarService foobarService = new FoobarService();
        private CategoryService categoryService = new CategoryService();
 
        private List<SelectListItem> CategorySelectListItems(string selected = "")
        {
            var categories = this.categoryService.GetAll();
            var items = new List<SelectListItem>();
 
            var selectedCategories = string.IsNullOrWhiteSpace(selected)
                ? null
                : selected.Split(',');
 
            foreach (var c in categories)
            {
                items.Add(item: new SelectListItem()
                {
                    Value = c.CategoryID.ToString(),
                    Text = c.CategoryName,
                    Selected = selectedCategories == null
                        ? false
                        : selectedCategories.Contains(c.CategoryID.ToString())
                });
            }
            return items;
        }
 
        public ActionResult Index()
        {
            var foobars = this.foobarService.GetAll();
            var categories = this.CategorySelectListItems();
 
            var result = new List<Foobar>();
            foreach ( var item in foobars )
            {
                var selectedList = item.Categories.Split(',').ToList();
                item.SelectedCategories = string.IsNullOrWhiteSpace(item.Categories)
                    ? ""
                    : string.Join(
                        ",",
                        categories.Where(x => selectedList.Contains(x.Value)).Select(x => x.Text));
 
                result.Add(item);
            }
 
            return View(result.ToList());
        }
 
        public ActionResult Details(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Foobar foobar = this.foobarService.GetOne(id.Value);
            if (foobar == null)
            {
                return HttpNotFound();
            }
 
            var items = this.CategorySelectListItems(foobar.Categories);
            foobar.SelectedCategories = string.IsNullOrWhiteSpace(foobar.Categories)
                ? ""
                : string.Join(",", items.Where(x => x.Selected).Select(x => x.Text)); 
 
            return View(foobar);
        }
 
        public ActionResult Create()
        {
            var items = this.CategorySelectListItems();
            ViewBag.CategoryItems = items;
 
            return View();
        }
 
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(string name, string[] categories)
        {
            var foobar = new Foobar
            {
                Name = name,
                Categories = string.Join(",", categories)
            };
 
            if (ModelState.IsValid)
            {
                this.foobarService.Create(foobar);
                return RedirectToAction("Index");
            }
 
            var items = this.CategorySelectListItems();
            ViewBag.CategoryItems = items;
 
            return View(foobar);
        }
 
        public ActionResult Edit(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Foobar foobar = this.foobarService.GetOne(id.Value);
            if (foobar == null)
            {
                return HttpNotFound();
            }
 
            var items = this.CategorySelectListItems(foobar.Categories);
            ViewBag.CategoryItems = items;
 
            return View(foobar);
        }
 
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(Guid id, string name, string[] categories)
        {
            var foobar = this.foobarService.GetOne(id);
            if (foobar == null)
            {
                return RedirectToAction("Index");
            }
 
            if (ModelState.IsValid)
            {
                foobar.Name = name;
                foobar.Categories = string.Join(",", categories);
                this.foobarService.Update(foobar);
 
                return RedirectToAction("Index");
            }
 
            var items = this.CategorySelectListItems();
            ViewBag.CategoryItems = items;
 
            return View(foobar);
        }
 
        public ActionResult Delete(Guid? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Foobar foobar = this.foobarService.GetOne(id.Value);
            if (foobar == null)
            {
                return HttpNotFound();
            }
 
            var items = this.CategorySelectListItems(foobar.Categories);
            foobar.SelectedCategories = string.IsNullOrWhiteSpace(foobar.Categories)
                ? ""
                : string.Join(",", items.Where(x => x.Selected).Select(x => x.Text)); 
 
            return View(foobar);
        }
 
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(Guid id)
        {
            bool isExists = this.foobarService.IsExists(id);
            if (!isExists)
            {
                return RedirectToAction("Index");
            }
            this.foobarService.Delete(id);
            return RedirectToAction("Index");
        }
    }
}

 

Views

在 Create 與 Edit 的 View 原始碼裡,要特別注意的是最底下的Javascript Code,可千萬別忘了。

Create.cshtml

@using WebApplication1.Infrastructure.Enums
@model WebApplication1.Models.Foobar
 
@{
    ViewBag.Title = "Create";
}
 
<h2>Create</h2>
 
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
 
    <div class="form-horizontal">
        <h4>Foobar</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.Categories, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @*@Html.EditorFor(model => model.Categories, new { htmlAttributes = new { @class = "form-control" } })*@
                @*@Html.ValidationMessageFor(model => model.Categories, "", new { @class = "text-danger" })*@
 
                @Html.EditorFor(model => model.Categories,
                    "CheckBoxList",
                    new
                    {
                        TagName = "Categories",
                        CheckBoxItems = ViewBag.CategoryItems,
                        Position = Position.Vertical,
                        Numbers = 3
                    })
            </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>
}
 
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
 
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script type="text/javascript">
        $(function () {
            $('input[name="Categories"]').rules('add', {
                messages: {
                    required: "請至少選擇一個分類"
                }
            });
        });
    </script>
}
 

Edit.cshtml

@using WebApplication1.Infrastructure.Enums
@model WebApplication1.Models.Foobar
 
@{
    ViewBag.Title = "Edit";
}
 
<h2>Edit</h2>
 
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
 
    <div class="form-horizontal">
        <h4>Foobar</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.ID)
 
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>
 
        <div class="form-group">
            @Html.LabelFor(model => model.Categories, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @*@Html.EditorFor(model => model.Categories, new { htmlAttributes = new { @class = "form-control" } })*@
                @*@Html.ValidationMessageFor(model => model.Categories, "", new { @class = "text-danger" })*@
                @Html.EditorFor(model => model.Categories,
                    "CheckBoxList",
                    new
                    {
                        TagName = "Categories",
                        CheckBoxItems = ViewBag.CategoryItems,
                        Position = Position.Vertical,
                        Numbers = 3
                    })
 
            </div>
        </div>
 
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
 
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
          
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script type="text/javascript">
        $(function () {
            $('input[name="Categories"]').rules('add', {
                messages: {
                    required: "請至少選擇一個分類"
                }
            });
        });
    </script>
}

 

執行結果

Index (List)

image

Create

image

Details

image

Edit

image

Delete

image

 


文章內容的程式範例已經上傳到 GitHub,想要查看程式細節或是下載範例程式的朋友請自行前往。

GitHub Repository

MVC5_with_CheckBoxList_CRUD

image

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。