しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

ASP.NET MVC でドロップダウンリスト周りを良い感じに扱う

恐らく ASP.NET MVC で一番迷う人が多いと思うドロップダウンリストやラジオボタンですが、仕事でついに逃げられなくなったので堪忍して、まずはドロップダウンリストからいろいろとまとめました。

普通は DropDownList を作る時に SelectList などを引数として渡しますが、例えば null を渡した場合にはどうなるでしょう?

@Html.DropDownListFor(model => model.CategoryId, null)

正解はもちろん例外が投げられます。しかしメッセージに注目。

f:id:shiba-yan:20130201220907p:plain

そう、null を指定した場合には ViewData*1 に同名のキーがないか探しに行きます。

つまり、ViewBag に CategoryId という名前で選択項目を入れておけば、あとは HTML ヘルパーが良い感じに扱ってくれます。

public ActionResult Index()
{
    ViewBag.CategoryId = Enumerable.Range(1, 5).Select(p => new SelectListItem
    {
        Text = "項目" + p,
        Value = p.ToString()
    });

    return View();
}

これで実行してみると、以下のように選択項目が表示されました。

f:id:shiba-yan:20130201221349p:plain

次は、この CategoryId を表示させる時を考えてみます。スキャフォールディングだと DisplayFor を使ったコードが生成されますが、値がそのまま表示されてしまいます。

f:id:shiba-yan:20130201221837p:plain

やはり項目名が表示されてほしいですが、そういったヘルパーは用意されていないので自分で作ることにしました。

public static class DisplaySelectExtensions
{
    public static MvcHtmlString DisplaySelectFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        var name = ExpressionHelper.GetExpressionText(expression);
            
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        var value = metadata.Model.ToString();

        var selectList = (IEnumerable<SelectListItem>)htmlHelper.ViewData.Eval(name);

        return MvcHtmlString.Create(selectList.First(p => p.Value == value).Text);
    }
}

エラー処理はちょっと端折ってますが、これで DisplaySelectFor ヘルパーが完成しました。実際に使う場合は以下のような感じです。

@Html.DisplaySelectFor(model => model.CategoryId)

実際に動かしてみました。ちゃんと項目名が表示されていますね。

f:id:shiba-yan:20130201223644p:plain

選択項目はアクションと別でメソッドを作っておいて、ビューを返す前にそのメソッドを呼び出してセットすればいいでしょう。今度はラジオボタンについて書きたいと思います。

*1:ViewBag とも言う