しばやん雑記

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

ASP.NET MVC で Twitter Bootstrap を使ってみた (4)

前回は IsValid という拡張メソッドを用意して対応しましたが、今回は BeginForm のように IDisposable と using を使って書き換えてみます。

今回は拡張メソッドと IDisposable を実装したクラスを用意しました。実装は BeginForm と MvcForm クラスを参考にしています。

作成したコードは以下の通りです。難しいことはやっていなくて、単純にエラーの場合は error クラスを追加して、Dispose が呼ばれた時に閉じタグを出力しているだけです。

public static class BootstrapExtensions
{
    public static BootstrapField BeginField<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        var tagBuilder = new TagBuilder("div");
        tagBuilder.AddCssClass("clearfix");

        var name = ExpressionHelper.GetExpressionText(expression);
        var fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

        ModelState modelState;

        if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState) && modelState.Errors.Count > 0)
        {
            tagBuilder.AddCssClass("error");
        }

        htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));

        return new BootstrapField(htmlHelper.ViewContext);
    }
}

public class BootstrapField : IDisposable
{
    private bool _disposed;
    private readonly TextWriter _writer;

    public BootstrapField(ViewContext viewContext)
    {
        if (viewContext == null) {
            throw new ArgumentNullException("viewContext");
        }

        _writer = viewContext.Writer;
    }

    public void Dispose()
    {
        Dispose(true /* disposing */);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            _disposed = true;
            _writer.Write("</div>");
        }
    }
}

これで BeginField メソッドが使えるようになったので、ビューも書き換えます。using を使っているので、前回みたいに出し分けの必要がなくなり、パッと見で分かりやすくなりました。

@using (Html.BeginField(model => model.Name))
{
    @Html.LabelFor(model => model.Name)
    <div class="input">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name, null, new { @class = "help-inline" })
    </div>
}

それでは実行して確認をしてみます。スタイルが正しく反映されていることが分かりました。

f:id:shiba-yan:20120107235515p:image

そして出力された HTML も一応確認しておきます。

f:id:shiba-yan:20120107235717p:image

多少インデントがおかしくなってますが、閉じタグも正しく出力されていることが分かりました。これで結構スッキリしましたね。