Introducing DisplayText, DisplayTextFor, Id, IdFor, IdForModel.

Fixing CachedDataAnnotationsModelMetadata to support NullDisplayText.
This commit is contained in:
sornaks 2014-04-23 17:07:14 -07:00
parent 112a5ddc50
commit d63d998e95
12 changed files with 179 additions and 4 deletions

View File

@ -96,7 +96,8 @@ namespace MvcSample.Web
Address = "Dependents address",
Alive = false,
},
About = "I am a Software Engineer"
Profession = "Software Engineer",
About = "I like playing Football"
};
return user;

View File

@ -13,6 +13,8 @@ namespace MvcSample.Web.Models
public User Dependent { get; set; }
public bool Alive { get; set; }
public string Password { get; set; }
[DisplayFormat(ConvertEmptyStringToNull = true, NullDisplayText = "You can explain about your profession")]
public string Profession { get; set; }
public string About { get; set; }
public string Log { get; set; }
}

View File

@ -18,7 +18,7 @@
}
else
{
<h4 title="@Model.Name" class="@ViewBag.NullValue">Hello @Model.Name! Happy @(Model.Age)th birthday.</h4>
<h4 title="@Model.Name" class="@ViewBag.NullValue">Hello @Html.DisplayTextFor(model => model.Name)! Happy @(Model.Age)th birthday.</h4>
}
@{
@ -69,10 +69,18 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.Name</label>
<label class="control-label col-md-2">Model.Profession</label>
</td>
<td>
@Html.TextArea("About", "You can explain about your profession, hobbies etc.", 5, 40, htmlAttributes: new { style = "font-weight:bold" })
<input type="text" id="@Html.IdFor(model => model.Profession)" name="Profession" value='@Html.DisplayText("Profession")' />
</td>
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.About</label>
</td>
<td>
@Html.TextArea("About", "You can explain about your hobbies, work etc.", 5, 40, htmlAttributes: new { style = "font-weight:bold" })
</td>
</tr>
<tr>

View File

@ -258,6 +258,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
return GenerateDisplayName(metadata, expression);
}
/// <inheritdoc />
public HtmlString DisplayText(string name)
{
var metadata = ExpressionMetadataProvider.FromStringExpression(name, ViewData, MetadataProvider);
return GenerateDisplayText(metadata);
}
/// <inheritdoc />
public HtmlString DropDownList(string name, IEnumerable<SelectListItem> selectList, string optionLabel,
@ -291,6 +298,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
/// <inheritdoc />
public HtmlString Id(string name)
{
return GenerateId(name);
}
/// <inheritdoc />
public HtmlString Label(string expression, string labelText, object htmlAttributes)
{
@ -652,6 +665,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
return new HtmlString(Encode(resolvedDisplayName));
}
protected virtual HtmlString GenerateDisplayText(ModelMetadata metadata)
{
return new HtmlString(metadata.SimpleDisplayText);
}
protected HtmlString GenerateDropDown(ModelMetadata metadata, string expression,
IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes)
@ -760,6 +778,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributeDictionary);
}
protected virtual HtmlString GenerateId(string expression)
{
return new HtmlString(Encode(ViewData.TemplateInfo.GetFullHtmlFieldName(expression)));
}
protected virtual HtmlString GenerateLabel([NotNull] ModelMetadata metadata,
string htmlFieldName,
string labelText,

View File

@ -108,6 +108,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
return GenerateDisplayName(metadata, expressionText);
}
/// <inheritdoc />
public HtmlString DisplayTextFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression)
{
return GenerateDisplayText(GetModelMetadata(expression));
}
/// <inheritdoc />
public HtmlString EditorFor<TValue>(
@ -134,6 +140,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
/// <inheritdoc />
public HtmlString IdFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression)
{
return GenerateId(GetExpressionName(expression));
}
/// <inheritdoc />
public HtmlString LabelFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression, string labelText, object htmlAttributes)
{

View File

@ -15,5 +15,15 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
return htmlHelper.Name(string.Empty);
}
/// <summary>
/// Gets the full HTML field id for the current model.
/// </summary>
/// <param name="htmlHelper">The <see cref="HtmlHelper"/> instance that this method extends.</param>
/// <returns>An <see cref="HtmlString"/> that represents HTML markup.</returns>
public static HtmlString IdForModel([NotNull] this IHtmlHelper htmlHelper)
{
return htmlHelper.Id(string.Empty);
}
}
}

View File

@ -161,6 +161,16 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// </returns>
HtmlString DisplayName(string expression);
/// Returns the HtmlString corresponding to the property in the model specified by the name.
/// </summary>
/// <param name="name">
/// The string which identifies the object for which the HtmlString should be returned.</param>
/// <returns>
/// New <see cref="HtmlString"/> containing the display text. If the value is null,
/// then it returns the ModelMetadata.NullDisplayText.
/// </returns>
HtmlString DisplayText(string name);
/// <summary>
/// Returns a single-selection HTML {select} element using the specified name of the form field,
/// list items, option label, and HTML attributes.
@ -248,6 +258,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString Hidden(string name, object value, object htmlAttributes);
/// <summary>
/// Gets the Id of the given string.
/// </summary>
/// <param name="name">The string which identifies the object for which the Id should be returned.</param>
/// <returns>New <see cref="HtmlString"/> containing the Id.</returns>
HtmlString Id(string name);
/// <summary>
/// Returns an HTML label element and the property name of the property that is represented by the specified
/// expression.

View File

@ -70,6 +70,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString DisplayNameForInnerType<TInnerModel, TValue>(
[NotNull] Expression<Func<TInnerModel, TValue>> expression);
/// <summary>
/// Returns the HtmlString corresponding to the expression specified.
/// </summary>
/// <param name="expression">
/// The expression identifies the object for which the HtmlString should be returned.
/// </param>
/// <returns>
/// New <see cref="HtmlString"/> containing the display text. If the value is null,
/// then it returns the ModelMetadata.NullDisplayText.
/// </returns>
HtmlString DisplayTextFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression);
/// <summary>
/// Returns a single-selection HTML {select} element for the object that is represented
/// by the specified expression using the specified list items, option label, and HTML attributes.
@ -125,6 +137,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString HiddenFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
object htmlAttributes);
/// <summary>
/// Gets the Id of the given expression.
/// </summary>
/// <param name="expression">The expression identifies the object for which the Id should be returned.</param>
/// <returns>New <see cref="HtmlString"/> containing the Id.</returns>
HtmlString IdFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression);
/// <summary>
/// Returns an HTML label element and the property name of the property that is represented by the specified
/// expression.

View File

@ -31,6 +31,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
: base.ComputeConvertEmptyStringToNull();
}
protected override string ComputeNullDisplayText()
{
return PrototypeCache.DisplayFormat != null
? PrototypeCache.DisplayFormat.NullDisplayText
: base.ComputeNullDisplayText();
}
protected override string ComputeDescription()
{
return PrototypeCache.Display != null

View File

@ -17,11 +17,13 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
public abstract class CachedModelMetadata<TPrototypeCache> : ModelMetadata
{
private bool _convertEmptyStringToNull;
private string _nullDisplayText;
private string _description;
private bool _isReadOnly;
private bool _isComplexType;
private bool _convertEmptyStringToNullComputed;
private bool _nullDisplayTextComputed;
private bool _descriptionComputed;
private bool _isReadOnlyComputed;
private bool _isComplexTypeComputed;
@ -62,6 +64,24 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
}
public sealed override string NullDisplayText
{
get
{
if (!_nullDisplayTextComputed)
{
_nullDisplayText = ComputeNullDisplayText();
_nullDisplayTextComputed = true;
}
return _nullDisplayText;
}
set
{
_nullDisplayText = value;
_nullDisplayTextComputed = true;
}
}
public sealed override string Description
{
get
@ -118,6 +138,11 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return base.ConvertEmptyStringToNull;
}
protected virtual string ComputeNullDisplayText()
{
return base.NullDisplayText;
}
protected virtual string ComputeDescription()
{
return base.Description;

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Mvc.ModelBinding.Internal;
namespace Microsoft.AspNet.Mvc.ModelBinding
@ -20,6 +22,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
private int _order = DefaultOrder;
private IEnumerable<ModelMetadata> _properties;
private Type _realModelType;
private string _simpleDisplayText;
public ModelMetadata([NotNull] IModelMetadataProvider provider,
Type containerType,
@ -141,6 +144,21 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
}
}
public virtual string SimpleDisplayText
{
get
{
if (_simpleDisplayText == null)
{
_simpleDisplayText = ComputeSimpleDisplayText();
}
return _simpleDisplayText;
}
set { _simpleDisplayText = value; }
}
public virtual string TemplateHint { get; set; }
internal EfficientTypePropertyKey<Type, string> CacheKey
@ -177,6 +195,38 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
// return validatorProviders.SelectMany(provider => provider.GetValidators(this, validatorProviders));
//}
protected virtual string ComputeSimpleDisplayText()
{
if (Model == null)
{
return NullDisplayText;
}
var stringResult = Convert.ToString(Model, CultureInfo.CurrentCulture);
if (stringResult == null)
{
return string.Empty;
}
if (!stringResult.Equals(Model.GetType().FullName, StringComparison.Ordinal))
{
return stringResult;
}
var firstProperty = Properties.FirstOrDefault();
if (firstProperty == null)
{
return string.Empty;
}
if (firstProperty.Model == null)
{
return firstProperty.NullDisplayText;
}
return Convert.ToString(firstProperty.Model, CultureInfo.CurrentCulture);
}
private static EfficientTypePropertyKey<Type, string> CreateCacheKey(Type containerType, Type modelType, string propertyName)
{
// If metadata is for a property then containerType != null && propertyName != null

View File

@ -25,6 +25,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding.Test
// Assert
Assert.Equal(typeof(Exception), metadata.ContainerType);
Assert.True(metadata.ConvertEmptyStringToNull);
Assert.Null(metadata.NullDisplayText);
Assert.Null(metadata.Description);
Assert.Equal("model", metadata.Model);
Assert.Equal(typeof(string), metadata.ModelType);