上一篇「ASP.NET MVC - CheckBoxList 與 ValidationMessage (ASP.NET MVC 5 with Bootstrap3)」的說明是使用 Visual Studio 2013, ASP.NET MVC 5, Bootstrap 環境下所開發的,然而如果是使用 ASP.NET MVC 4 並且沒有使用 Bootstrap 的情況下又該如何操作呢?
兩者的最大差別是在於有無使用 Bootstrap,因為我上一篇是使用預設的 ASP.NET MVC 5 專案範本,所以預設就會使用 Bootstrap,所以在 CheckbBoxListExtensions.cs 裡建立 CheckBox Items 時就需要做一些調整,另外在檢視頁面裡也會有一些不同。
開發環境:Visual Studio 2012, ASP.NET MVC 4, .NET Framework 4, Entity Framework 5.0
前一篇文章:
ASP.NET MVC - CheckBoxList 與 ValidationMessage (ASP.NET MVC 5 with Bootstrap3)
專案的檔案目錄架構與上一篇文章的相同,
以下為這次所使用的 CheckBoxListExtensions.cs 內容,
CheckBoxListExtensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using MvcApplication1.Infrastructure.Enums;
namespace MvcApplication1.Infrastructure.Extensions
{
public static class CheckBoxListExtensions
{
#region -- CheckBoxList (Horizontal) --
/// <summary>
/// CheckBoxList.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="name">The name.</param>
/// <param name="listInfo">SelectListItem.</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> listInfo)
{
return htmlHelper.CheckBoxList(name, listInfo, (IDictionary<string, object>)null, 0);
}
/// <summary>
/// CheckBoxList.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="name">The name.</param>
/// <param name="listInfo">SelectListItem.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> listInfo,
object htmlAttributes)
{
return htmlHelper.CheckBoxList(name, listInfo, (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes), 0);
}
/// <summary>
/// CheckBoxList.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="name">The name.</param>
/// <param name="listInfo">The list info.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <param name="number">每個Row的顯示個數.</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> listInfo,
IDictionary<string, object> htmlAttributes,
int number)
{
if (String.IsNullOrEmpty(name))
{
throw new ArgumentException("必須給這些 CheckBoxList 一個 Tag Name", "name");
}
if (listInfo == null)
{
throw new ArgumentNullException("listInfo", "必須要給List<SelectListItem> listInfo");
}
var selectListItems = listInfo as SelectListItem[] ?? listInfo.ToArray();
if (!selectListItems.Any())
{
throw new ArgumentException("List<SelectListItem> listInfo 至少要有一組資料", "listInfo");
}
var sb = new StringBuilder();
var lineNumber = 0;
foreach (var info in selectListItems)
{
lineNumber++;
var builder = new TagBuilder("input");
if (info.Selected)
{
builder.MergeAttribute("checked", "checked");
}
builder.MergeAttributes<string, object>(htmlAttributes);
builder.MergeAttribute("type", "checkbox");
builder.MergeAttribute("value", info.Value);
builder.MergeAttribute("name", name);
builder.MergeAttribute("id", string.Format("{0}_{1}", name, info.Value));
sb.Append(builder.ToString(TagRenderMode.Normal));
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", string.Format("{0}_{1}", name, info.Value));
labelBuilder.InnerHtml = info.Text;
sb.Append(labelBuilder.ToString(TagRenderMode.Normal));
if (number == 0 || (lineNumber % number == 0))
{
sb.Append("<br />");
}
}
return MvcHtmlString.Create(sb.ToString());
}
#endregion
#region -- CheckBoxListVertical --
/// <summary>
/// Checks the box list vertical.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="name">The name.</param>
/// <param name="listInfo">The list info.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <param name="columnNumber">The column number.</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxListVertical(this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> listInfo,
IDictionary<string, object> htmlAttributes,
int columnNumber = 1)
{
if (String.IsNullOrEmpty(name))
{
throw new ArgumentException("必須給這些 CheckBoxList 一個 Tag Name", "name");
}
if (listInfo == null)
{
throw new ArgumentNullException("listInfo", "必須要給 List<CheckBoxListInfo> listInfo");
}
var selectListItems = listInfo as SelectListItem[] ?? listInfo.ToArray();
if (!selectListItems.Any())
{
throw new ArgumentException("List<CheckBoxListInfo> listInfo 至少要有一組資料", "listInfo");
}
var dataCount = selectListItems.Count();
// calculate number of rows
var rows = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(dataCount) / Convert.ToDecimal(columnNumber)));
if (dataCount <= columnNumber || dataCount - columnNumber == 1)
{
rows = dataCount;
}
var wrapBuilder = new TagBuilder("div");
wrapBuilder.MergeAttribute("style", "float: left; light-height: 25px; padding-right: 5px;");
var wrapStart = wrapBuilder.ToString(TagRenderMode.StartTag);
var wrapClose = string.Concat(wrapBuilder.ToString(TagRenderMode.EndTag), " <div style=\"clear:both;\"></div>");
var wrapBreak = string.Concat("</div>", wrapBuilder.ToString(TagRenderMode.StartTag));
var sb = new StringBuilder();
sb.Append(wrapStart);
var lineNumber = 0;
foreach (var info in selectListItems)
{
var builder = new TagBuilder("input");
if (info.Selected)
{
builder.MergeAttribute("checked", "checked");
}
builder.MergeAttributes<string, object>(htmlAttributes);
builder.MergeAttribute("type", "checkbox");
builder.MergeAttribute("value", info.Value);
builder.MergeAttribute("name", name);
builder.MergeAttribute("id", string.Format("{0}_{1}", name, info.Value));
sb.Append(builder.ToString(TagRenderMode.Normal));
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", string.Format("{0}_{1}", name, info.Value));
labelBuilder.InnerHtml = info.Text;
sb.Append(labelBuilder.ToString(TagRenderMode.Normal));
lineNumber++;
if (lineNumber.Equals(rows))
{
sb.Append(wrapBreak);
lineNumber = 0;
}
else
{
sb.Append("<br/>");
}
}
sb.Append(wrapClose);
return MvcHtmlString.Create(sb.ToString());
}
#endregion
#region -- CheckBoxList (Horizonal, Vertical) --
/// <summary>
/// Checks the box list.
/// </summary>
/// <param name="htmlHelper">The HTML helper.</param>
/// <param name="name">The name.</param>
/// <param name="listInfo">The list info.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <param name="position">The position.</param>
/// <param name="number">Position.Horizontal則表示每個Row的顯示個數, Position.Vertical則表示要顯示幾個Column</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper,
string name,
IEnumerable<SelectListItem> listInfo,
IDictionary<string, object> htmlAttributes,
Position position = Position.Horizontal,
int number = 0)
{
if (String.IsNullOrEmpty(name))
{
throw new ArgumentException("必須給這些 CheckBoxList 一個 Tag Name", "name");
}
if (listInfo == null)
{
throw new ArgumentNullException("listInfo", "必須要給List<SelectListItem> listInfo");
}
var selectListItems = listInfo as SelectListItem[] ?? listInfo.ToArray();
if (!selectListItems.Any())
{
throw new ArgumentException("List<SelectListItem> listInfo 至少要有一組資料", "listInfo");
}
var sb = new StringBuilder();
var lineNumber = 0;
switch (position)
{
case Position.Horizontal:
foreach (var info in selectListItems)
{
lineNumber++;
sb.Append(CreateCheckBoxItem(info, name, htmlAttributes));
if (number == 0 || (lineNumber % number == 0))
{
sb.Append("<br />");
}
}
sb.Append("<br />");
break;
case Position.Vertical:
var dataCount = selectListItems.Count();
// 計算最大顯示的列數(rows)
var rows = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(dataCount) / Convert.ToDecimal(number)));
if (dataCount <= number || dataCount - number == 1)
{
rows = dataCount;
}
var wrapBuilder = new TagBuilder("div");
wrapBuilder.MergeAttribute("style", "float: left; light-height: 25px; padding-right: 5px;");
var wrapStart = wrapBuilder.ToString(TagRenderMode.StartTag);
var wrapClose = string.Concat(wrapBuilder.ToString(TagRenderMode.EndTag), " <div style=\"clear:both;\"></div>");
var wrapBreak = string.Concat("</div>", wrapBuilder.ToString(TagRenderMode.StartTag));
sb.Append(wrapStart);
foreach (var info in selectListItems)
{
lineNumber++;
sb.Append(CreateCheckBoxItem(info, name, htmlAttributes));
if (lineNumber.Equals(rows))
{
sb.Append(wrapBreak);
lineNumber = 0;
}
else
{
sb.Append("<br/>");
}
}
sb.Append(wrapClose);
break;
}
return MvcHtmlString.Create(sb.ToString());
}
/// <summary>
/// Creates the check box item.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="name">The name.</param>
/// <param name="htmlAttributes">The HTML attributes.</param>
/// <returns></returns>
internal static string CreateCheckBoxItem(SelectListItem info, string name, IDictionary<string, object> htmlAttributes)
{
var sb = new StringBuilder();
var builder = new TagBuilder("input");
if (info.Selected)
{
builder.MergeAttribute("checked", "checked");
}
builder.MergeAttributes<string, object>(htmlAttributes);
builder.MergeAttribute("type", "checkbox");
builder.MergeAttribute("value", info.Value);
builder.MergeAttribute("name", name);
builder.MergeAttribute("id", string.Format("{0}_{1}", name, info.Value));
sb.Append(builder.ToString(TagRenderMode.Normal));
var labelBuilder = new TagBuilder("label");
labelBuilder.MergeAttribute("for", string.Format("{0}_{1}", name, info.Value));
labelBuilder.InnerHtml = info.Text;
sb.Append(labelBuilder.ToString(TagRenderMode.Normal));
return sb.ToString();
}
#endregion
}
}
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Infrastructure.Services;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
private readonly CategoryService categoryService = new CategoryService();
private List<SelectListItem> categorySelectListItems
{
get
{
var categories = this.categoryService.GetAll();
var items = new List<SelectListItem>();
foreach (var c in categories)
{
items.Add(item: new SelectListItem()
{
Value = c.CategoryID.ToString(),
Text = c.CategoryName
});
}
return items;
}
}
public ActionResult Index()
{
var items = this.categorySelectListItems;
ViewBag.CategoryItems = items;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Foo instance)
{
var items = this.categorySelectListItems;
ViewBag.CategoryItems = items;
if (ModelState.IsValid)
{
return View();
}
return View(instance);
}
}
}
~/Views/Shared/EditorTemplates/CheckBoxList.cshtml
先建立 CheckBoxList.cshtml 的 EditorTemplates,這邊的內容就與上一篇所建立的 EditorTemplates 有些不同了,最大的差別就在於最後的 ValidationMessage 的地方,
@using MvcApplication1.Infrastructure.Enums
@using MvcApplication1.Infrastructure.Extensions
@{
var require = false;
object validationMessage = string.Empty;
var validationAttributes = Html.GetUnobtrusiveValidationAttributes("");
if (validationAttributes.ContainsKey("data-val")
&&
validationAttributes.ContainsKey("data-val-required"))
{
require = true;
if (!validationAttributes.TryGetValue("data-val-required", out validationMessage))
{
validationMessage = "This field is required.";
}
validationAttributes.Add("required", "required");
}
var tagName = ViewData["TagName"] == null
? "CheckBoxList"
: (string)ViewData["TagName"];
var checkboxItems = ViewData["CheckBoxItems"] == null
? new List<SelectListItem>()
: (IEnumerable<SelectListItem>)ViewData["CheckBoxItems"];
var position = ViewData["Position"] == null
? Position.Horizontal
: (Position)ViewData["Position"];
var numbers = 0;
if (ViewData["Numbers"] == null)
{
numbers = 1;
}
else if (!int.TryParse(ViewData["Numbers"].ToString(), out numbers))
{
numbers = 1;
}
}
@Html.CheckBoxList(
tagName,
checkboxItems,
new RouteValueDictionary(validationAttributes),
position,
numbers)
@if (require)
{
<span class="field-validation-valid" data-valmsg-for="@(tagName)" data-valmsg-replace="false">
@validationMessage
</span>
}
~/Views/Home/Index.cshtml
再來就主要顯示的 View,差別也是在 ValidationMessage 的部份,上一篇還需要另外使用 jQuery 去處理訊息的顯示,而這一篇並不需要這麼做,
@using MvcApplication1.Infrastructure.Enums
@model MvcApplication1.Models.Foo
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>Foo</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Categories)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Categories,
"CheckBoxList",
new
{
TagName = "Categories",
CheckBoxItems = ViewBag.CategoryItems,
Position = Position.Horizontal,
Numbers = 3
})
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
執行結果
什麼都不填、不勾選,直接按下「Create」
在分類項目裡勾選一個
以下為完整的操作過程
以上
沒有留言:
張貼留言