Html 带有 .NET MVC 3 Razor EditorFor 扩展的 Html5 占位符?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5824124/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 08:18:13  来源:igfitidea点击:

Html5 Placeholders with .NET MVC 3 Razor EditorFor extension?

asp.net-mvchtmleditorfor

提问by seekay

Is there a way to write the Html5 placeholderusing @Html.EditorFor, or should I just use the TextBoxFor extension i.e.

有没有办法使用@Html.EditorFor编写Html5 占位符,或者我应该只使用 TextBoxFor 扩展名,即

@Html.TextBoxFor(model => model.Title, new { @placeholder = "Enter title here"})

Or would it make sense to write our own custom extension that can maybe use the 'Description' display attribute via DataAnnotations (similar to this)?

或者编写我们自己的自定义扩展是否有意义,该扩展可以通过 DataAnnotations 使用“描述”显示属性(类似于)?

Of course, then the same question applies to 'autofocus' as well.

当然,同样的问题也适用于“自动对焦”。

采纳答案by Darin Dimitrov

You may take a look at the following articlefor writing a custom DataAnnotationsModelMetadataProvider.

您可以查看以下文章来编写自定义DataAnnotationsModelMetadataProvider.

And here's another, more ASP.NET MVC 3ish way to proceed involving the newly introduced IMetadataAwareinterface.

这是另一种更多的 ASP.NET MVC 3ish 方式来处理新引入的IMetadataAware接口。

Start by creating a custom attribute implementing this interface:

首先创建一个实现此接口的自定义属性:

public class PlaceHolderAttribute : Attribute, IMetadataAware
{
    private readonly string _placeholder;
    public PlaceHolderAttribute(string placeholder)
    {
        _placeholder = placeholder;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["placeholder"] = _placeholder;
    }
}

And then decorate your model with it:

然后用它装饰你的模型:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Next define a controller:

接下来定义一个控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }
}

A corresponding view:

相应的视图:

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Title)
    <input type="submit" value="OK" />
}

And finally the editor template (~/Views/Shared/EditorTemplates/string.cshtml):

最后是编辑器模板 ( ~/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>

回答by Daniel Liuzzi

As smnbss comments in Darin Dimitrov's answer, Promptexists for exactly this purpose, so there is no need to create a custom attribute. From the the documentation:

正如 Darin Dimitrov 的回答中 smnbss 评论的那样,Prompt正是出于此目的而存在的,因此无需创建自定义属性。从文档中:

Gets or sets a value that will be used to set the watermark for prompts in the UI.

获取或设置一个值,该值将用于为 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 Watermarkproperty, 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:

然后,该文本可以方便地放置在ModelMetadata.Watermark. 开箱即用,MVC 3 中的默认模板忽略该Watermark属性,但使其工作非常简单。您需要做的就是调整默认字符串模板,告诉 MVC 如何呈现它。只需像 Darin 一样编辑 String.cshtml,除了不是从 获取水印ModelMetadata.AdditionalValues,而是直接从ModelMetadata.Watermark

~/Views/Shared/EditorTemplates/String.cshtml:

~/Views/Shared/EditorTemplates/String.cshtml:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })

And that is it.

就是这样。

As you can see, the key to make everything work is the placeholder = ViewData.ModelMetadata.Watermarkbit.

如您所见,使一切正常工作的关键是placeholder = ViewData.ModelMetadata.Watermark一点。

If you also want to enable watermarking for multi-line textboxes (textareas), you do the same for MultilineText.cshtml:

如果您还想为多行文本框 (textareas) 启用水印,则对 MultilineText.cshtml 执行相同操作:

~/Views/Shared/EditorTemplates/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 })

回答by The Pax Bisonica

I actually prefer to use the display name for the placeholder text majority of the time. Here is an example of using the DisplayName:

我实际上更喜欢在大多数情况下使用占位符文本的显示名称。以下是使用 DisplayName 的示例:

  @Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })

回答by Mike Eshva

I've wrote such a simple class:

我写了一个这么简单的类:

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.

注意提示参数。在这种情况下,我使用来自资源的字符串进行本地化,但您可以只使用字符串,避免使用 ResourceType 参数。

回答by xicooc

I use this way with Resource file (don't need Prompt anymore !)

我用这种方式处理资源文件(不再需要提示!)

@Html.TextBoxFor(m => m.Name, new 
{
     @class = "form-control",
     placeholder = @Html.DisplayName(@Resource.PleaseTypeName),
     autofocus = "autofocus",
     required = "required"
})

回答by Vladimir

Here is a solution I made using the above ideas that can be used for TextBoxFor and PasswordFor:

这是我使用上述想法制作的解决方案,可用于 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));
    }
}

回答by Sel

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.

我认为创建自定义 EditorTemplate 不是一个好的解决方案,因为您需要关心不同情况下许多可能的模板:字符串、数字、组合框等。其他解决方案是对 HtmlHelper 的自定义扩展。

Model:

模型:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Html helper extension:

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);

}

}

A corresponding view:

相应的视图:

@Html.BsEditorFor(x => x.Title)