As smnbss comments in Darin Dimitrov's answer, Prompt exists for exactly this purpose, so there is no need to create a custom attribute. From the the documentation:
Gets or sets a value that will be used
to set the watermark for prompts in
the UI.
To use it, just decorate your view model's property like so:
[Display(Prompt = "numbers only")]
public int Age { get; set; }
This text is then conveniently placed in ModelMetadata.Watermark. Out of the box, the default template in MVC 3 ignores the Watermark property, but making it work is really simple. All you need to do is tweaking the default string template, to tell MVC how to render it. Just edit String.cshtml, like Darin does, except that rather than getting the watermark from ModelMetadata.AdditionalValues, you get it straight from ModelMetadata.Watermark:
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);
}
}
The usage as such:
@Html.TextBoxFor(model => model.AddressSuffix, new {placeholder = Html.WatermarkFor(model => model.AddressSuffix)})
And property in a viewmodel:
[Display(ResourceType = typeof (Resources), Name = "AddressSuffixLabel", Prompt = "AddressSuffixPlaceholder")]
public string AddressSuffix
{
get { return _album.AddressSuffix; }
set { _album.AddressSuffix = value; }
}
Notice Prompt parameter. In this case I use strings from resources for localization but you can use just strings, just avoid ResourceType parameter.
I think create a custom EditorTemplate is not good solution, beause you need to care about many possible tepmlates for different cases: strings, numsers, comboboxes and so on.
Other solution is custom extention to HtmlHelper.
Model:
public class MyViewModel
{
[PlaceHolder("Enter title here")]
public string Title { get; set; }
}
Html helper extension:
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);