Вы можете прочитать следующую статью, чтобы написать обычай DataAnnotationsModelMetadataProvider
.
А вот еще один, более подходящий для ASP.NET MVC 3 способ продолжить работу с использованием недавно представленного интерфейса IMetadataAware .
Начните с создания настраиваемого атрибута, реализующего этот интерфейс:
public class PlaceHolderAttribute : Attribute, IMetadataAware
{
private readonly string _placeholder;
public PlaceHolderAttribute(string placeholder)
{
_placeholder = placeholder;
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["placeholder"] = _placeholder;
}
}
А потом украсьте им свою модель:
public class MyViewModel
{
[PlaceHolder("Enter title here")]
public string Title { get; set; }
}
Затем определите контроллер:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
}
Соответствующий вид:
@model MyViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.Title)
<input type="submit" value="OK" />
}
И, наконец, шаблон редактора ( ~/Views/Shared/EditorTemplates/string.cshtml
):
@{
var placeholder = string.Empty;
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("placeholder"))
{
placeholder = ViewData.ModelMetadata.AdditionalValues["placeholder"] as string;
}
}
<span>
@Html.Label(ViewData.ModelMetadata.PropertyName)
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { placeholder = placeholder })
</span>
Prompt
работать.Поскольку комментарии smnbss в ответе Дарина Димитрова
Prompt
существуют именно для этой цели, поэтому нет необходимости создавать настраиваемый атрибут . Из документации:Чтобы использовать его, просто украсьте свойство вашей модели представления следующим образом:
[Display(Prompt = "numbers only")] public int Age { get; set; }
Затем этот текст удобно помещается в
ModelMetadata.Watermark
. Стандартный шаблон в MVC 3 по умолчанию игнорируетWatermark
свойство, но заставить его работать очень просто. Все, что вам нужно сделать, это настроить строковый шаблон по умолчанию, чтобы сообщить MVC, как его отображать. Просто отредактируйте String.cshtml, как это делает Дарин, за исключением того, что вместо того, чтобы получать водяной знакModelMetadata.AdditionalValues
, вы получаете его прямо изModelMetadata.Watermark
:~ / Views / Shared / EditorTemplates / String.cshtml:
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })
Вот и все.
Как видите, ключ к тому, чтобы все работало, - это
placeholder = ViewData.ModelMetadata.Watermark
бит.Если вы также хотите включить водяные знаки для многострочных текстовых полей (текстовых полей), сделайте то же самое для MultilineText.cshtml:
~ / Views / Shared / EditorTemplates / MultilineText.cshtml:
@Html.TextArea("", ViewData.TemplateInfo.FormattedModelValue.ToString(), 0, 0, new { @class = "text-box multi-line", placeholder = ViewData.ModelMetadata.Watermark })
источник
Prompt
атрибутом. Для получения дополнительной информации об этих шаблонах вы можете обратиться к этому замечательному сообщению Брэда Уилсона: bradwilson.typepad.com/blog/2009/10/…DisplayAttribute
(включая Prompt) можно локализовать. Вам просто нужно указать ResourceType в аннотации:[Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]
. Вот и все. Текст водяного знака теперь берется из ключевой AgeGroup в ресурсе PeopleResources .EditorTemplates
Папка @FrancisRodgers по умолчанию отсутствует; вы просто создаете в своейViews\Shared
папке (илиViews\{ControllerName}
если хотите, чтобы она была специфичной для определенного контроллера). Затем вы помещаете свои шаблоны .cshtml в эту папку, и все будет в порядке.На самом деле я предпочитаю использовать отображаемое имя для текста-заполнителя в большинстве случаев. Вот пример использования DisplayName:
@Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })
источник
Я написал такой простой класс:
public static class WatermarkExtension { public static MvcHtmlString WatermarkFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { var watermark = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Watermark; var htmlEncoded = HttpUtility.HtmlEncode(watermark); return new MvcHtmlString(htmlEncoded); } }
Использование как таковое:
@Html.TextBoxFor(model => model.AddressSuffix, new {placeholder = Html.WatermarkFor(model => model.AddressSuffix)})
И свойство во вьюмодели:
[Display(ResourceType = typeof (Resources), Name = "AddressSuffixLabel", Prompt = "AddressSuffixPlaceholder")] public string AddressSuffix { get { return _album.AddressSuffix; } set { _album.AddressSuffix = value; } }
Обратите внимание на параметр приглашения. В этом случае я использую строки из ресурсов для локализации, но вы можете использовать только строки, просто избегайте параметра ResourceType.
источник
Я использую этот способ с файлом ресурсов (больше не нужно подсказывать!)
@Html.TextBoxFor(m => m.Name, new { @class = "form-control", placeholder = @Html.DisplayName(@Resource.PleaseTypeName), autofocus = "autofocus", required = "required" })
источник
Вот решение, которое я сделал, используя приведенные выше идеи, которые можно использовать для TextBoxFor и PasswordFor:
public static class HtmlHelperEx { public static MvcHtmlString TextBoxWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); return htmlHelper.TextBoxFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark)); } public static MvcHtmlString PasswordWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes) { var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); return htmlHelper.PasswordFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark)); } } public static class HtmlAttributesHelper { public static IDictionary<string, object> AddAttribute(this object htmlAttributes, string name, object value) { var dictionary = htmlAttributes == null ? new Dictionary<string, object>() : htmlAttributes.ToDictionary(); if (!String.IsNullOrWhiteSpace(name) && value != null && !String.IsNullOrWhiteSpace(value.ToString())) dictionary.Add(name, value); return dictionary; } public static IDictionary<string, object> ToDictionary(this object obj) { return TypeDescriptor.GetProperties(obj) .Cast<PropertyDescriptor>() .ToDictionary(property => property.Name, property => property.GetValue(obj)); } }
источник
Я думаю, что создание пользовательского EditorTemplate не является хорошим решением, потому что вам нужно позаботиться о многих возможных tepmlates для разных случаев: строки, числа, поля со списком и так далее. Другое решение - индивидуальное расширение HtmlHelper.
Модель:
public class MyViewModel { [PlaceHolder("Enter title here")] public string Title { get; set; } }
Вспомогательное расширение HTML:
public static MvcHtmlString BsEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, string htmlClass = "") { var modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); var metadata = modelMetadata; var viewData = new { HtmlAttributes = new { @class = htmlClass, placeholder = metadata.Watermark, } }; return htmlHelper.EditorFor(expression, viewData);
}
Соответствующий вид:
@Html.BsEditorFor(x => x.Title)
источник