[ASP.net MVC 4] Controller如何取得Html Table裡各個Cell格子的值
前言
ASP.net MVC新手上路\(^O^)/
過沒多久就發現到相較以往寫WebForm時,畫面上拉一個GridView控制項
postback後,就可以在GridView的RowDataBound事件裡取得GridView裡各個Cell的值(可能用 .FindControl()方式)
那ASP.net MVC的Html Table呢?
把集合資料顯示在View的Html Table之後,按下submit,表單提交
在Controller想要對Table裡各個Cell的值做更動後再丟回View顯示Table更動後的結果…如此的需求
話說試出辦法前,我還不知道ViewModel裡的參考型別屬性該怎麼跟View Binding (逃~
經過這關,自己的ViewModel和View的繫結又更進一步認識
回到主題,要解決「在Controller的Action內取得Html Table裡各個Cell格子的值」
重點就是:每個Cell塞一個hidden欄位和注意name的命名(用索引方式)
聽起來基本,但一開始我還有點小卡關XD”
範例實作
在Models資料夾裡加入MemberViewModel.cs、Book.cs、Company.cs
因為我要順便紀錄ViewModel的參考型別屬性如何Binding網頁標籤,所以才會有Book和Company類別
MemberViewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationHtmlTable.Models
{
public class MemberViewModel
{
/// <summary>
/// 會員名稱
/// </summary>
public string MemberName { get; set; }
private List<string> _NickNames = new List<string>();
/// <summary>
/// 多個暱稱
/// </summary>
public List<string> NickNames { get { return this._NickNames; } set { this._NickNames = value; } }
/// <summary>
/// 擁有多本書
/// </summary>
public List<Book> Books { get; set; }
/// <summary>
/// 屬於哪一家公司
/// </summary>
public Company Company { get; set; }
}
}
Book
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationHtmlTable.Models
{
public class Book
{
/// <summary>
/// 書名
/// </summary>
public string BookName { get; set; }
/// <summary>
/// 書本大小
/// </summary>
public string BookSize { get; set; }
}
}
Company
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcApplicationHtmlTable.Models
{
public class Company
{
/// <summary>
/// 公司人數
/// </summary>
public int PeopleNumber { get; set; }
/// <summary>
/// 是否為硬工作
/// </summary>
public bool IsHardWork { get; set; }
}
}
Controller加入HomeController.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplicationHtmlTable.Models;
namespace MvcApplicationHtmlTableBind.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 一開始進入表單
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult Index()
{
MemberViewModel vm = new MemberViewModel();
InitData(vm);
return View(vm);
}
/// <summary>
/// 初始化資料(假裝這是從DB撈出來的資料)
/// </summary>
/// <param name="vm"></param>
private static void InitData(MemberViewModel vm)
{
vm.MemberName = "王大明";
vm.NickNames = new List<string>() {
"小明","明兄","明明"
};
vm.Books = new List<Book>(){
new Book() { BookName="ASP.NET MVC 4開發實戰" , BookSize="1000x1000"},
new Book() { BookName = "ASP.NET MVC4網站開發美學", BookSize = "200x200" }
};
vm.Company = new Company() { PeopleNumber = 800, IsHardWork = true };
}
/// <summary>
/// 表單提交
/// </summary>
/// <param name="act"></param>
/// <param name="vm"></param>
/// <param name="myFile"></param>
/// <returns></returns>
[HttpPost]
public ActionResult Index(MemberViewModel vm)
{
this.LogWrite(vm);
return View(vm);
}
/// <summary>
/// 寫Log查看表單post的結果
/// </summary>
/// <param name="vm"></param>
private void LogWrite(MemberViewModel vm)
{
//寫Log - 暱稱
using (FileStream fs = new FileStream(@"D:\myLog.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
foreach (string strNickName in vm.NickNames)
{
sw.WriteLine("暱稱:" + strNickName);
}
sw.Close();
}
//寫Log - 書藉
using (FileStream fs = new FileStream(@"D:\myLog.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
foreach (Book objBook in vm.Books)
{
sw.WriteLine(objBook.BookName + "," + objBook.BookSize);
}
sw.Close();
}
//寫Log - 公司
using (FileStream fs = new FileStream(@"D:\myLog.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("公司人數:" + vm.Company.PeopleNumber);
sw.WriteLine("是否為硬工作:" + vm.Company.IsHardWork);
sw.Close();
}
}
}
}
重點的View完整代碼:
Index.cshtml
@model MvcApplicationHtmlTable.Models.MemberViewModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script type="text/javascript" src="@Url.Content("~/Scripts/jquery-2.0.0.min.js")"></script>
</head>
<body>
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data", name = "myForm" }))
{
<div>
會員姓名:@Html.TextBoxFor(m => m.MemberName)
<br />
會員暱稱:
<table border="1">
@*input系列的欄位才會自動Bind ViewModel,可以使用hidden欄位,把要傳給Controller的值隱藏起來*@
<!--最好使用for loop,有index變數可用-->
@for (int i = 0; i < Model.NickNames.Count; i++)
{
<tr>
<td>@Model.NickNames[i] @Html.HiddenFor(m => m.NickNames[i])</td>
</tr>
}
</table>
<br />
書籍:
<table border="1">
@for (int i = 0; i < Model.Books.Count; i++)
{
<tr>
<td>@Model.Books[i].BookName @Html.HiddenFor(m => m.Books[i].BookName)</td>
<td>@Model.Books[i].BookSize @Html.HiddenFor(m => m.Books[i].BookSize)</td>
</tr>
}
</table>
<br />
公司人數:@Html.TextBoxFor(Model => Model.Company.PeopleNumber)<br />
是否為硬工作:
@Html.RadioButtonFor(Model => Model.Company.IsHardWork, true) 是
@Html.RadioButtonFor(Model => Model.Company.IsHardWork, false) 否
</div>
<input type="submit" value="提交" />
}
</body>
</html>
圖解說明:
執行結果:
執行的網頁原始碼:集合的name都變成陣列型式,物件的name則為該物件.屬性名
按下提交按鈕後,透過寫出來的Log觀察,也確實抓到Html Table裡各Cell的值
結語
由於Table裡每個Cell偷塞了hidden欄位
到Controller那邊除了用ViewModel抓值外也可以使用FormCollection的GetValue(string name)或GetValues(string name)來抓值
不過還是用ViewModel才可以享受到強型別的好處
另外,Table若要整合 編輯或刪除 連結,可以在點選後用Ajax向Server進行異動後,callback function裡refresh整個table,讓每個Cell裡的hidden欄位值和name都更新,這樣表單post後
Controller接到的才會是正確的集合順序
參考文章:Getting values from the html to the controller
文章範例專案檔下載,放到MSDN期滿
以上
先有這樣的初步認識,下一篇介紹進階用法:[ASP.net MVC 4] 多張上傳圖片預覽,不使用Session和js套件的方式