前回は 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> }
それでは実行して確認をしてみます。スタイルが正しく反映されていることが分かりました。
そして出力された HTML も一応確認しておきます。
多少インデントがおかしくなってますが、閉じタグも正しく出力されていることが分かりました。これで結構スッキリしましたね。