ASP.NET MVC 5 でドロップダウンリストを使用する – ViewModel 編

ASP.NET MVC で、ドロップダウンリストを使用する方法について調べた結果をまとめてみました。

今回は ViewModel 編ということで、ドロップダウンリストの選択肢を表す ViewModel を作成し、Html.DropDownListFor メソッド を使用してドロップダウンリストを描画します。

環境

Windows 8.1 Home Edition
Visual Studio Community 2015 Update 2
ASP.NET MVC 5.2.3

目的

直近 10 年が選択肢となるドロップダウンリストを表示する。

手順

■ ビューモデルの作成

ここでは、以下の 2 つのビューモデル作成します。

  • 年のドロップダウンリストの選択肢(の 1 件)を表すビューモデル
  • ページ全体を表すビューモデル
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Tk2.MvcTips.Models
{
    // ドロップダウンリストの選択肢を表す ViewModel です。
    public class YearViewModel
    {
        // 選択肢の値をセットします。
        public int Value { get; set; }

        // 選択肢として表示するテキストを取得するためのプロパティ。
        // ここでは値に" 年"を足して、 "2016 年" と表示されるようにしています。
        public string DisplayText
        {
            get
            {
                return $"{this.Value} 年";
            }
        }
    }

    // ページに必要な情報を全て持つ ViewModel です。
    // View はこの ViewModel から値を取得するようにしています。
    public class DropDownListViewModel
    {
        // ドロップダウンリストで選択している値を取得または設定するためのプロパティです。
        [Required]
        [Display(Name = "年")]
        public int Year { get; set; }

        // ドロップダウンリストの選択肢をセットします。
        // ※ ViewBag で代用も可能。
        public IEnumerable<YearViewModel> YearOptions { get; set; }
    }
}

ポイントとしては、YearViewModel に、

  • ドロップダウンで選択した値と連動する Year プロパティ
  • 選択肢を設定するための YearOptions プロパティ

の両方を定義していることです。
YearOptions プロパティの目的は 「View に選択肢を渡すこと!」です。
なので、これは ViewBag でも代用可能です。

「MVC なのに何故 ビューモデルなの?モデルじゃないの?」と思われるかもしれませんが、以下の理由から ビューモデルとして実装しています。

  • ドロップダウンリストの選択肢はあくまで ビュー を意識したものなので、 モデル に持つのは違和感がある。
    (モデルというと EntitiyFramework などでそのまま DB にマッピングされる対象となるが、
    そこにドロップダウンリストの選択肢をもっているのはおかしいと思う為。)
  • ビューモデルを使用したほうが実用的だと思った為。
    MVC のスキャフォールディングで作成するような、
    単一のモデルをそのままビューに表示して CRUD 処理を行うようなページって、
    そんなに作らんのちゃうかなーと思っています。
    (モデルをそのままビューに出力するときは、選択肢は ViewBag で持つことになると思います。)

■ コントローラーの作成

コントローラーには、以下のメソッドを定義しています。

  • GET 用の Create メソッド
  • POST 用の Create メソッド
  • 年の選択肢を取得する GetYearOptions メソッド
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Tk2.MvcTips.Models;

namespace Tk2.MvcTips.Controllers
{
    public class DropDownListController : Controller
    {
        public ActionResult Create()
        {
            var vm = new DropDownListViewModel();

            // ここでビューモデルに選択肢をセットしています。
            vm.YearOptions = this.GetYearOptions();

            return View(vm);
        }

        [HttpPost]
        public ActionResult Create(DropDownListViewModel vm)
        {
            // もう一度ビューモデルに選択肢をセットしています。
            // Post されてこの箇所に来た時点で、
            // YearOptions プロパティは null になっているので、
            // 再度セットする必要があります。
            vm.YearOptions = this.GetYearOptions();

            return View(vm);
        }

        // 年の選択肢を取得するためのメソッドです。
        private IEnumerable<YearViewModel> GetYearOptions()
        {
            // 直近の 10 年を選択肢として取得する。
            return Enumerable
                .Range(DateTime.Now.Year - 9, 10)
                .Select(t => new YearViewModel() { Value = t });
        }
    }
}

注意点として、POST 用の Create メソッドでも、再度 DropDwonListViewModel の YearOptions プロパティに選択肢をセットしてやる必要があります。
(vm.YearOptions は、ここでは null になっています。)

■ ビューの作成

ビューでは、YearOptions プロパティを SelectList に変換し、Html.DropDownListFor メソッドを使用して、ドロップダウンリストを出力します。

@model Tk2.MvcTips.Models.DropDownListViewModel

@using (Html.BeginForm())
{
    <div class="form-horizontal">
        <h4>ドロップダウンリスト - ViewModel 編</h4>
        <hr />
        <div class="form-group">
            @Html.LabelFor(model => model.Year, htmlAttributes: new { @class = "control-label col-sm-2" })
            <div class="col-sm-10">

                @Html.DropDownListFor(
                    model => model.Year,
                    new SelectList(Model.YearOptions, "Value", "DisplayText"),
                    "年を選択",
                    new { @class = "form-control" })

                @Html.ValidationMessageFor(model => model.Year, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

結果

以下のように、ドロップダウンリストが出力されます。
DropDownList_ViewModel_1

DropDownList_ViewModel_2

Tk2

映画とかゲームとかが好きです。 はやく引退して悠々自適な生活したい。

コメントを残す