[ASP.NET MVC] @Html.DropDownList() 、@Html.DropDownListFor() 和 <select> 與<option>

要產生 <select> 和 <option> ,利用 System.Web.Mvc 命名空間下的 SelectListItem 類型,可製造出下拉選單,在 Controller 或 Model 中先建好資料:

  using System.Web.Mvc;
  List<SelectListItem> cities = new List<SelectListItem>()
  {
    new SelectListItem{ Text = "台南", Value = "Tainan" },
    new SelectListItem{ Text = "高雄", Value = "Kaohsiung" },
    new SelectListItem{ Text = "台中", Value = "Taichiung" },
    new SelectListItem{ Text = "桃園", Value = "Taoyuan" },
    new SelectListItem{ Text = "台北", Value = "Taipei" }
  };
  cities.Where(c => c.Text == "桃園")
        .FirstOrDefault()
        .Selected = true;             // Selected 屬性表示預設是哪一個選項被選取
      
  ViewBag.cities = cities;            // 利用 ViewBag 將資料帶去 View
  return View();
然後在 View 中:
  @{                                         // ViewBag 不用轉型,但要先宣告,
    IEnumerable<SelectListItem> cities = ViewBag.cities;     // 不能直接寫在 DropDownList() 內
  }
  @Html.DropDownList("city"                  // 第一個引數是做為 id 和 name,
                      , cities )             // 不可 null 或 string.Empty
                       
  // 會產生:
  <select id="city" name="city">
    <option value="Tainan">台南</option>
    <option value="Kaohsiung">高雄</option>
    <option value="Taichiung">台中</option>
    <option selected="selected" value="Taoyuan">桃園</option>
    <option value="Taipei">台北</option>
  </select>

也可加上 HTML Attribute,例如樣式或事件,在第三個引數:

  @{
    IEnumerable<SelectListItem> cities = ViewBag.cities;
  }
  @Html.DropDownList("city"
                      , cities
                      , new { onchange = "changeCity()"} )
                       
  // 會產生:
  <select id="city" name="city" onchange="changeCity()">
    <option value="Tainan">台南</option>
    <option value="Kaohsiung">高雄</option>
    <option value="Taichiung">台中</option>
    <option selected="selected" value="Taoyuan">桃園</option>
    <option value="Taipei">台北</option>
  </select>

另外有強型別的 @Html.DropDownListFor(),例如 Student 物件,有個 List<SelectListItem> Hobby 屬性,將他繫結到 View:

  Student student = new Student();
  student.Hobby = new List<SelectListItem>()
  {
    new SelectListItem{ Text = "爬山", Value = "MountainClimbing" },
    new SelectListItem{ Text = "唱歌", Value = "Singing" },
    new SelectListItem{ Text = "打電玩", Value = "Game" },
  };
  return View(student);      // 物件傳入 View()

而 View 中:

  @model prjMvc.Models.Student

  @Html.DropDownListFor(m => m.Hobby, null)     // 第二參數也可用完整的 Model.Hobby 
  
  // 會產生:
  
  <select id="Hobby" name="Hobby">              // id 和 name 已繫結
    <option value="MountainClimbing">爬山</option>
    <option value="Singing">唱歌</option>
    <option value="Game">打電玩</option>
  </select>

Selected 失效的 bug

上面的例子如果加上 Seleted = true 會發現沒有用:

  Student student = new Student();
  student.Hobby = new List<SelectListItem>()
  {
    new SelectListItem{ Text = "爬山", Value = "MountainClimbing" },
    new SelectListItem{ Text = "唱歌", Value = "Singing" },
    new SelectListItem{ Text = "打電玩", Value = "Game" , Selected = true },
  };                                         // 最後一個加了 Selected = true
  return View(student);
  @model prjMvc.Models.Student

  @Html.DropDownListFor(m => m.Hobby, null)     // 使用強型別
  
  // 會產生:
  
  <select id="Hobby" name="Hobby">
    <option value="MountainClimbing">爬山</option>
    <option value="Singing">唱歌</option>
    <option value="Game">打電玩</option>        <!-- selected 不見了 -->
  </select>

這是一個 bug,解答來自 Stack OverFlow : SelectListItem selected = true not working in view answerd by vibs2006,如果 name 和 Model 的某個屬性 prop 同名,則 Selected 會全部被覆蓋掉,所以強型別 DropDownListFor() 就不能用了,只能用 DropDownList(),而且給定的 name 還不能和 Model 的 prop 同名:

  @model prjMvc.Models.Student

  @Html.DropDownListFor(m => m.Hobby, null)          // Selected 形同失效

  @Html.DropDownListFor(m => m.Hobby, Model.Hobby)   // Selected 形同失效

  @Html.DropDownList("Hobby", Model.Hobby)           // Selected 形同失效

  @Html.DropDownList("FavoriteHobby", Model.Hobby)   // Selected 會出現

由於這個 bug ,所以比較好的設計,是另外放一個專門接收值的屬性,例如:

  using System.Web.Mvc;
  namespace prjMvc.Models.Student
  {
    public class Student
    {
      public string FavoriteHobby { get; set; }
      public List<SelectListItem> Hobby { get; set; }
    }
  }

留言