I have a requirement to roll my own BeginLabel helper for Mvc. I checked/stole the concept from the Mvc source for the 开发者_StackOverflowhtml.beginForm / ajax.beginForm methods.
public static Label BeginLabel(this HtmlHelper htmlHelper)
{
TagBuilder tagBuilder = new TagBuilder("label");
HttpResponseBase response = htmlHelper.ViewContext.HttpContext.Response;
response.Write(tagBuilder.ToString(TagRenderMode.StartTag));
return new Label(response);
}
The Label simply implements IDisposable interface to enable closing off the label:
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
_httpResponse.Write("</label>");
}
}
Usage looks like this:
@using (Html.BeginLabel())
{
@Html.TextBoxFor(f => f.FirstName)
@Html.ValidationMessageFor(f => f.FirstName)
}
It looks like i'm missing something as the labels always get rendered at the top of the html and while this is obvious to me because i'm writing to the response, I can't see how the native BeginForm() is achieving this. Can anyone shed any light on this?
public class MvcLabel : IDisposable
{
// Fields
private bool _disposed;
private readonly TextWriter _writer;
public MvcLabel(ViewContext viewContext)
{
if (viewContext == null)
{
throw new ArgumentNullException("viewContext");
}
this._writer = viewContext.Writer;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
this._disposed = true;
this._writer.Write("</label>");
}
}
public void EndLabel()
{
this.Dispose(true);
}
}
and
public static class HtmlHelperExtension
{
// Methods
public static MvcLabel BeginLabel(this HtmlHelper html, string expression)
{
return html.BeginLabel(expression, null);
}
public static MvcLabel BeginLabel(this HtmlHelper html, string expression, string labelText)
{
return LabelHelper(html, ModelMetadata.FromStringExpression(expression, html.ViewData), expression, labelText);
}
public static MvcLabel BeginLabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
return html.BeginLabelFor<TModel, TValue>(expression, null);
}
public static MvcLabel BeginLabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string labelText)
{
return LabelHelper(html, ModelMetadata.FromLambdaExpression<TModel, TValue>(expression, html.ViewData), ExpressionHelper.GetExpressionText(expression), labelText);
}
public static MvcLabel BeginLabelForModel(this HtmlHelper html)
{
return html.BeginLabelForModel(null);
}
public static MvcLabel BeginLabelForModel(this HtmlHelper html, string labelText)
{
return LabelHelper(html, html.ViewData.ModelMetadata, string.Empty, labelText);
}
public static void EndLabel(this HtmlHelper htmlHelper)
{
htmlHelper.ViewContext.Writer.Write("</label>");
}
internal static MvcLabel LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName, string labelText = null)
{
string str = labelText ?? (metadata.DisplayName ?? (metadata.PropertyName ?? htmlFieldName.Split(new char[] { '.' }).Last<string>()));
TagBuilder tagBuilder = new TagBuilder("label");
tagBuilder.Attributes.Add("for", TagBuilder.CreateSanitizedId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
html.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));
if (!string.IsNullOrEmpty(str))
{
tagBuilder = new TagBuilder("span");
tagBuilder.SetInnerText(str);
html.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.Normal));
}
return new MvcLabel(html.ViewContext);
}
}
Hope i can help others...
精彩评论