miso_soup3 Blog

主に ASP.NET 関連について書いています。

検証付きドロップダウンリストを実装する

ドロップダウンリスト(あるいは、DropDownList、セレクトリスト、SelectList、コンボボックス、ComboBox とも言う)の実装は、ASP.NET MVC を初めた 90 % の人がググるであろう、最初のハードルです。

今回は、ドロップダウンリストの実装例を検証機能も含めて紹介します。 

  • 概要
  • HTTP のやりとり
  • ドロップダウンリスト実装のポイント
    • ドロップダウンリストの表示
    • ドロップダウンリストの HTML
    • 選択した値をモデルバインドさせる
    • 検証エラーで再表示するときも忘れずに
  • 補足
  • 実装手順

概要

GET:~/Person/Create で次のような画面を表示します。色を選択できるドロップダウンリストが含まれています。
f:id:miso_soup3:20131204020438p:plain

名前と好きな色、どちらかを入力・選択しないで Create ボタンを押すと、次のようにエラーメッセージが表示されます。(好きな色を”選択して下さい”にしても、エラーメッセージが表示されます。)
f:id:miso_soup3:20131204020645p:plain

名前と好きな色、両方を入力して Create ボタンを押すと、~/Person/CreateCompleted に遷移し、”登録完了!”というメッセージが表示されます。
f:id:miso_soup3:20131204020901p:plain

JavaScript によるクライアント側の検証は行わないものとします。
(= Create ボタンを押すと、必ずサーバー側へリクエストが送信されます。)

HTTP のやりとり

ブラウザとサーバーの HTTP のやりとりを、簡単に確認します。

f:id:miso_soup3:20131204023003p:plain

ポイントは、ドロップダウンリストを表示する方法と、
サーバー側からブラウザへ HTML を送信するとき―②と④の2ヵ所でドロップダウンリストを表示(用意)しなければいけないことの2つです。
このポイントについては後で説明します。

ドロップダウンリスト実装のポイント

ドロップダウンリストの実装のポイントを説明します。説明に使うコードは、次のセクション「実装」にて使用しているコードです。初めての場合や、手っ取り早く理解したい方は、ここを飛ばして「実装」を試すことをお勧めします。

ドロップダウンリストの HTML

ドロップダウンリストは、次のようにタグで表されます。

f:id:miso_soup3:20131204032104p:plain

フォーム送信時には、name 属性である FavoriteColorId と、選択した項目の value 属性の値が送信されます。例えば、「あか」を選択した場合は、「FavoriteColorId=1」が送信されます。(フォーム送信の仕組みについては、WEB フォーム送信の仕組みを理解する をご覧ください。)

ここでのポイントは、選択された値―「FavoriteColorId=1」の「1」を受け取るためのクラスとプロパティを用意する必要がある、ということです。(後に登場する CreatePersonModel クラスの FavoriteColorId プロパティになります。)

ドロップダウンリストの表示

ドロップダウンリストを表示するには、Controller 側で SelectList(System.Web.Mvc 名前空間)に、選択項目のソースを格納する必要があります。
具体的には、下のようなコードになります。

f:id:miso_soup3:20131204032006p:plain

今回は、選択項目のソースをデータベースから取り出すことを想定しました。(他には Enum から取り出すケースがあります。)GetColorList() メソッドで、ダミーの Color コレクションを用意しています。(実際は、データベースに接続してコレクションを用意すると思います。)

SelectList のコンストラクタの第1引数には、ソースとなるデータのコレクションを(厳密には IEnumerable 型のインスタンスを)。
第2引数には、ドロップダウンリストの value 属性の値に該当するプロパティ名を(今回の場合は、Color クラスの Id プロパティ)。
第3引数には、ドロップダウンリストの項目名(画面から確認できる”あか・き・みどり”といったテキスト)に該当するプロパティ名を(今回の場合は、Color クラスの Name プロパティ)設定します。

ビューは、次のように Html.DropDownListFor を利用します。

f:id:miso_soup3:20131204034819p:plain

第1引数には、選択した値を格納(モデルバインド)したいプロパティを。
第2引数には、ドロップダウンリストのソースである SelectList のインスタンスを。
第3引数には、オプションラベル(先頭に表示される、空を表す選択項目名)を設定します。

選択した値をモデルバインドさせる

f:id:miso_soup3:20131204033759p:plain

ドロップダウンリストで選択された値は、CreatePersonModel クラスの FavoriteColorId プロパティに、モデルバインドの仕組みによって格納されます。(CreatePersonModel クラスは、PersonController クラスの Create メソッドの引数に定義することにより、モデルバインドの対象となります。)

モデルのクラスでは、ドロップダウンリストの項目ソースを表す ColorSelectList プロパティと、選択した値を表す FavoriteColorId プロパティを用意することになります。

今回、FavoriteColorId の型を int の Nullable 型にした理由は、ドロップダウンリストで”選択して下さい”が選択されて送信された場合に、FavoriteColorId プロパティに null をモデルバインドさせるためです。[Required]検証属性がついているプロパティに null が代入されている場合、ASP.NET MVC の検証機構は”検証エラー”と判断します。

検証エラーで再表示するときも忘れずに

検証エラーでビューを再表示するときも、ドロップダウンリストの用意を忘れないようにします。

f:id:miso_soup3:20131204035823p:plain

2回も用意するの?と不思議に思うかもしれませんが、用意しないとドロップダウンリストを表示できません。

補足

SelectList は、IEnumerable<SelectListItem> でも代用が可能です。その場合、もちろんインスタンス生成方法は変わりますが、そのまま SelectListItem のコレクションのインスタンスを生成すれば OK です。

f:id:miso_soup3:20131204035411p:plain


ドロップダウンリストの実装におけるポイントは以上です。
最後に実装方法を記載して終わります。

実装

プロジェクトの用意

Visual Studio のサイト から、Visual Studio Express 2013 for Web(以下、VS Express 2013)をインストールします。無償です。

VS Express 2013 を開き、メニューから ファイル>新規作成>プロジェクト を選択します。
「ASP.NET Web アプリケーション」を選択し、OK します。ここでは、プロジェクト名を「WebApplication4」としました。(プロジェクト名は任意ですが、後のコードにてこのプロジェクト名を参照していますので、コードをコピペする時は注意。)

「MVC」を選択し OK します。

モデル(クラス)を用意

プロジェクトの作成が終了したら、クラスを2つ用意します。ソリューションエクスプローラーを表示しておきます。

ビュー(HTML)を描画するためのモデル、「CreatePersonModel クラス」を作成します。「Models」フォルダを右クリック>追加>クラス で「CreatePersonModel.cs」を作成します。クラスには下のようにプロパティ Name、FavoriteColorId、SelectList を用意します。

CreatePersonModel.cs

using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace WebApplication4.Models
{
	public class CreatePersonModel
	{
		[Required(ErrorMessage="{0} が必要です。")]
		[Display(Name = "名前")]
		public string Name { get; set; }

		[Required(ErrorMessage = "{0} を選択して下さい。")]
		[Display(Name = "好きな色")]
		public int? FavoriteColorId { get; set; }

		/// <summary>
		/// 色選択リスト
		/// </summary>
		public SelectList ColorSelectList { get; set; }
	}
}

次に、ドロップダウンリストの選択アイテムの素となる「Color クラス」を作成します。先ほどと同じように「Models」フォルダに「Color.cs」クラスを作成します。プロパティは下のように Id と Name を持たせます。

Color.cs

using System;

namespace WebApplication4.Models
{
	public class Color
	{
		public int Id { get; set; }
		public String Name { get; set; }
	}
}
PersonController の用意

次は、コントローラークラス「PersonController.cs」を追加します。「Controllers」フォルダを右クリックし、追加>コントローラー>MVC 5 コントローラー - 空 を選択します。
コントローラー名は「PersonController」とします。作成したら、下のようにメソッドを追加します。

PersonController.cs

using System.Collections.Generic;
using System.Diagnostics;
using System.Web.Mvc;
using WebApplication4.Models;

namespace WebApplication4.Controllers
{
    public class PersonController : Controller
    {
		// GET: /Person/Create
		[HttpGet]
		public ActionResult Create()
		{
			//色のコレクションを取得します
			IEnumerable<Color> colors = GetColorList();

			var model = new CreatePersonModel();
			model.ColorSelectList = new SelectList(colors, "Id", "Name");
			return View(model);
		}

		// POST: /Person/Create
		[HttpPost]
		public ActionResult Create(CreatePersonModel model)
		{
			if (!ModelState.IsValid)
			{
				IEnumerable<Color> colors = GetColorList();
				model.ColorSelectList = new SelectList(colors, "Id", "Name");
				return View(model);
			}

			//本来はここで、登録処理を行う
			Debug.WriteLine("Name : {0}", model.Name);
			Debug.WriteLine("FavoriteColorId : {0}", model.FavoriteColorId);

			return RedirectToAction("CreateCompleted");
		}

		// GET: /Person/CreateCompleted
		[HttpGet]
		public ActionResult CreateCompleted()
		{
			return View();
		}

		// 色のコレクションを取得します
		private IEnumerable<Color> GetColorList()
		{
			return new List<Color>()
			{
				new Color(){ Id = 1, Name = "あか"},
				new Color(){ Id = 2, Name = "き"},
				new Color(){ Id = 3, Name = "みどり"}
			};
		}
	}
}
ビューの追加

作成した PersonController クラスの Create() メソッドを右クリックし、ビューの追加を選択します。次に表示されるダイアログは、そのまま「追加」を押します。
「Person」フォルダに Create.cshtml が追加されます。

Create.cshtml のコードは下のようになります。(最初のプロジェクト名に注意)

Create.csHtml

@model WebApplication4.Models.CreatePersonModel

@{
	ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm())
{
	<div class="form-horizontal">

		<div class="form-group">
			@Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
			<div class="col-md-10">
				@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
				@Html.ValidationMessageFor(model => model.Name)
			</div>
		</div>

		<div class="form-group">
			@Html.LabelFor(model => model.FavoriteColorId, new { @class = "control-label col-md-2" })
			<div class="col-md-10">
				@Html.DropDownListFor(model => model.FavoriteColorId, Model.ColorSelectList,
					"選択して下さい。", new { @class = "form-control" })
				@Html.ValidationMessageFor(model => model.FavoriteColorId)
			</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>
}

次は、登録完了のビューを用意します。先ほどと同じように、PersonController クラスの CreateCompleted() メソッドを右クリックし、ビューの追加を選択し、そのまま「追加」を押します。コードは下の通りです。

@{
	ViewBag.Title = "CreateCompleted";
}

<h4>登録完了!</h4>

@Html.ActionLink("登録へ", "Create")

以上で実装は終了です。F5 でプロジェクトをデバッグ実行し、「http://localhost:XXX/Person/Create」にアクセスし、操作を試します。

by 深夜連絡 ASP.NET MVC な Web アプリ Advent Calendar 2013 3 日目