[ASP.net MVC 4] 生成控制項的方式選擇(以文字方塊TextBox為例)

[ASP.net MVC 4] 生成控制項的方式選擇(以文字方塊TextBox為例)

前言

有一段時間沒玩ASP.net MVC,最近接案又開始重溫起

把一些小小心得整理上來

要在ASP.net MVC的View裡產生控制項的話

大概有三種做法:※XXX為TextBox、DropDownList、CheckBox…等等自行代入

@Html.XXXFor()

@Html.XXX()

<input type=”” name=””  />

這三種各有特性,該挑選哪一個,請見以下說明

 

 

事前準備

在Models資料夾加入一個TestViewModel.cs


using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplicationNullableBindTest.Models
{
    public class TestViewModel
    {
        //方字方塊最常見和string型別binding
        public string strMsg { get; set; }

    }
}

在Controllers資料夾加入控制器HomeController.cs


using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using WebApplicationNullableBindTest.Models;

namespace WebApplicationNullableBindTest.Controllers
{
    public class HomeController : Controller
    {
        
        [HttpGet]
        public ActionResult Index()
        {
            
            return View(); 
        }

        [HttpPost]
        public ActionResult Index(TestViewModel vm)
        {
            ViewData["showMsg"] = vm.strMsg;
            
            return View(vm);
        }
    }
}

加入檢視


@*View宣告使用ViewModel,享受強型別的好處*@
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
</head>
<body>
      @using(Html.BeginForm("Index","Home",FormMethod.Post)){
    
          <!--裡面待會要放TextBox-->
          <div>


          </div>
          
          
        <input type="submit" value="提交" />
        <div>
            剛剛輸入的值:@ViewData["showMsg"]
        </div>
    
    }
  

</body>
</html>

 

說明

1.只要View有宣告使用ViewModel

不管三種方式中的任何一種,只要控制項的name名稱和ViewModel(以本文為例就是TestViewModel類別)的屬性相同,控制項的值會自動Binding到ViewModel

所以在controller的HttpPost的Index()才會用TestViewModel當參數傳進去


        public ActionResult Index(TestViewModel vm)
        {
            ViewData["showMsg"] = vm.strMsg;
            
            return View(vm);
        }

 

2. View自己對自己Post後

使用<input type=”” name=”” />的話,value會清空

@Html.XXX()和@Html.XXXFor()這兩種Html Helper,value不會清空

這情況很像以前開發Web Form時,使用Server Control和Html Control的差別


@*View宣告使用ViewModel,享受強型別的好處*@
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
</head>
<body>
      @using(Html.BeginForm("Index","Home",FormMethod.Post)){
    
          <!--裡面待會要放TextBox-->
          <div>
              <input type="text" name="strMsg" />

          </div>
          
          
        <input type="submit" value="提交" />
        <div>
            剛剛輸入的值:@ViewData["showMsg"]
        </div>
    
    }
  

</body>
</html>

 

image

使用@Html.XXX() Html Helper方式


@*View宣告使用ViewModel,享受強型別的好處*@
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
</head>
<body>
      @using(Html.BeginForm("Index","Home",FormMethod.Post)){
    
          <!--裡面待會要放TextBox-->
          <div>
              @Html.TextBox("strMsg")
              
          </div>
          
          
        <input type="submit" value="提交" />
        <div>
            剛剛輸入的值:@ViewData["showMsg"]
        </div>
    
    }
  

</body>
</html>

image

所以目前可歸納,開發時儘量使用Html Helper來生成控制項對使用者操作比較方便

2013.5.10追記,這個還要再搭配Post的Action方法,有沒有傳入相對應的類別(該類別有屬性名稱在畫面上),值才會被keep住

以本文為例

我在Models資料夾已加入一個TestViewModel類別


using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplicationNullableBindTest.Models

{
    public class TestViewModel
    {

        public string strMsg { get; set; }
    }
}

畫面上可不用宣告使用ViewModel



<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Test</title>
</head>
<body>
    <div>
        @using(Html.BeginForm("Index","Home",FormMethod.Post)){
            @Html.TextBox("strMsg")
            
            <input type="submit" value="提交" />
        
        }
    </div>
</body>
</html>

Action方法傳入的參數必加TestViewModel,就可以keep住畫面上輸入的值了


        public ActionResult Index(TestViewModel vm)
        {
           
            return View();
        }

 

 

3. @Html.XXX()控制項的name給字串型別,@Html.XXXFor()控制項的name命名來自Model的屬性、有intellisense輔助

以下使用@Html.XXXFor()來生成控制項,雖然打字比@Html.XXX()多


@*View宣告使用ViewModel,享受強型別的好處*@
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
</head>
<body>
      @using(Html.BeginForm("Index","Home",FormMethod.Post)){
    
          <!--裡面待會要放TextBox-->
          <div>
             @Html.TextBoxFor(Model=>Model.strMsg)
              
          </div>
          
          
        <input type="submit" value="提交" />
        <div>
            剛剛輸入的值:@ViewData["showMsg"]
        </div>
    
    }
  

</body>
</html>

使用@Html.XXXFor()除了有intellisense好處(較不會打錯字)

還有如果當ViewModel的屬性更改名稱的話


using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace WebApplicationNullableBindTest.Models
{
    public class TestViewModel
    {
       public string strChangeMsg { get; set; }

    }
}

View在編譯時期,Visual Studio即可得知錯誤,讓開發者方便更改錯誤地方

image

↑此特性是@Html.XXX()所沒有的

所以此點可歸納優先使用@Html.XXXFor()再來是@Html.XXX()

不過@Html.XXXFor()有個前提:須在View最上方用@model宣告ViewModel

 

 

總結

在View裡,優先產生控制項的使用順序

@Html.XXXFor()

@Html.XXX()

<input type=”” name=”” value=”” />

當然,這順序並不是絕對

個人在開發過程中有碰到bool?型別,View要用CheckBox來Binding

如果用@Html.CheckBoxFor(Model=>Model.屬性.HasValue?Model.屬性.Value:false)的話

程式會出錯:範本只能配合欄位存取、屬性存取、單一維度陣列索引或單一參數自訂索引子運算式使用。

image

↑改用@Html.CheckBox(“Model屬性名稱”)即可Binding bool?型別解決問題

至於ViewModel的各屬性型別如何適當地生成各種控制項,有空再整理一個指南

 

 

 

 

 

Html Helper表單控制項的MSDN文件:使用 HTML Helper 在 ASP.NET MVC 呈現表單