【问题标题】:What is the tag helper equivalent of Html.EditorFor什么是标签助手等价于 Html.EditorFor
【发布时间】:2020-10-08 13:29:21
【问题描述】:

如果我在字符串类型的属性上使用Html.EditorFor,则生成的元素默认为“文本”类型的<input>

或者,如果属性具有属性[DataType(DataType.MultilineText)],则Html.EditorFor 生成<textarea>

但是,如果我使用标签助手,那么我必须为自己选择元素类型,例如<input asp-for='MyProperty' />。这可以使用有关属性的信息来确定输入的类型(文本、日期、电子邮件等),但将始终生成 <input>,而不是 <textarea>,即使我有 [DataType] 属性。

这似乎违背了我可以在一个地方从单行更改为多行的想法:模型。现在我必须浏览所有相关视图并自己进行更改。

在我看来,我完全有可能编写自己的标签助手,它可以查看属性属性并决定是生成 <input> 还是 <textarea>,但我找不到任何对预定义的引用.

有没有这种预定义的标签助手,如果没有,有什么原因吗?

【问题讨论】:

  • 这就是重点。当您在视图中并使用 EditorFor 时,您希望相信框架会为您选择合适的“编辑器”(输入、文本区域、使用日期/时间选择器等)。当您想要更多控制时,您可以在视图本身的特定情况下直接编写所需的 html 标记。如果您希望它在特定视图中显示为文本区域,请阅读,然后只需写 <textarea asp-for="MyProperty"></textarea>
  • 是的,您可以自己编写,如果这对您的特定情况有帮助,它可以像一些表达式树魔术一样简单,并将其传递给标签助手中的 EditorFor。但是EditorFor 有什么问题,除了“它看起来像代码而不是 html”?
  • 我不同意这就是重点。如果您想获得比Html.EditorFor 提供的更精确的控制,那么您可以使用Html.TextAreaFor 等,标签助手是无关紧要的。标签助手的要点是它们的语法比 Html 助手更方便,但似乎没有 EditorFor 助手的等价物。

标签: c# asp.net-core asp.net-core-tag-helpers


【解决方案1】:

使用与 Html.EditorFor 等效的标签助手的新方法是在标签助手本身中使用旧的 HtmlHelper。看看这个博客,你可能会找到你需要的东西,或者改用我的代码。 http://blog.techdominator.com/article/using-html-helper-inside-tag-helpers.html

 [HtmlTargetElement("editor", TagStructure = TagStructure.WithoutEndTag, 
    Attributes = ForAttributeName + "," + TemplateAttributeName)]
public class EditorTagHelper : TagHelper
{
    private IHtmlHelper _htmlHelper;

    private const string ForAttributeName = "asp-for";
    private const string TemplateAttributeName = "asp-template";

    [HtmlAttributeName(ForAttributeName)]
    public ModelExpression For { get; set; }


    [HtmlAttributeName(TemplateAttributeName)]
    public string Template { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContext { get; set; }

    public EditorTagHelper(IHtmlHelper htmlHelper)
    {
        _htmlHelper = htmlHelper;
    }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        if (output == null)
            throw new ArgumentNullException(nameof(output));

        output.SuppressOutput();

        (_htmlHelper as IViewContextAware).Contextualize(ViewContext);

        output.Content.SetHtmlContent(_htmlHelper.Editor(For.Name, Template));

        await Task.CompletedTask;
    }
}

【讨论】:

  • 当我将此代码用于输入元素时,我发现我的表单验证器 (FluentValidation) 不再触发。知道为什么会这样吗?
【解决方案2】:

对于它的价值,您讨论的某些内容实际上是InputTagHelper 的一部分。它将根据属性类型(布尔复选框等)在不同的输入类型之间动态切换。但是,正如您所指出的,它只会生成一个输入,因为它明确地是一个 input taghelper。 textareas 有一个完全不同的 taghelper。 技术上可以创建一个自定义标签助手来实现您想要的,但是需要做大量的工作。如需参考,请参阅source for InputTagHelper。此时,无法从标签助手调用其他标签助手,因此您基本上需要将InputTagHelper 的整个代码与TextAreaTagHelper 的代码合并到自定义标签助手中。通过从InputTagHelper 继承自定义标签助手,然后覆盖Process 以调用base.Process(),然后自定义输出,您可能会为自己节省一点工作。然而,再一次,这比这里的简单答案要复杂得多。

长短,是的,这可以通过自定义标签助手来实现,但需要一些工作。就我个人而言,考虑到这只是一种情况:使用 textarea 切换输入以实现多行输入,我认为这比它的价值要多一些,如果您愿意,从技术上讲,您仍然可以使用EditorFor

如果你想走这条路,微软有an article/tutorial 可以给你一个好的开始。除此之外,只需研究现有助手的来源即可。

【讨论】:

  • 这不仅仅是文本区域,这只是一个例子。 Html.Editor 也会根据UIHint 属性选择不同的输出。
  • UIHint 是一个完全不同的野兽。在EditorFor 中,这会导致加载一个完全不同的模板,因为EditorFor 是所谓的“模板化助手”。标签助手是不是模板化的助手。如果你需要这样的功能,你应该坚持EditorFor
【解决方案3】:

到目前为止,还没有标签助手可以实现这一点,但您可以创建自己的类似标签。

    [HtmlTargetElement("editor-for")]
    public class EditorForTagHelper : TagHelper
    {
        private const string TemplateValuesDictionaryName = "template-all-data";
        private const string HtmlAttributesDictionaryName = "html-all-data";

        private IDictionary<string, object> _templateValues;
        private IDictionary<string, string> _htmlAttributes;

        public ModelExpression For
        {
            get; set;
        }

        /// <summary>
        /// Display template name  to use for rendering
        /// </summary>
        public string Template
        {
            get; set;
        }

        /// <summary>
        /// Additional parameters for the template.
        /// </summary>
        [HtmlAttributeName(TemplateValuesDictionaryName, DictionaryAttributePrefix = "template-")]
        public IDictionary<string, object> TemplateValues
        {
            get
            {
                if (_templateValues == null)
                    _templateValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

                return _templateValues;
            }
            set
            {
                _templateValues = value;
            }
        }

        /// <summary>
        /// Additional htmlattributes for the control template
        /// </summary>
        [HtmlAttributeName(HtmlAttributesDictionaryName, DictionaryAttributePrefix = "html-")]
        public IDictionary<string, string> HtmlAttributes
        {
            get
            {
                if (_htmlAttributes == null)
                    _htmlAttributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

                return _htmlAttributes;
            }
            set
            {
                _htmlAttributes = value;
            }
        }


        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext ViewContext
        {
            get; set;
        }

        /// <summary>
        /// Creates a new <see cref="DisplayForTagHelper"/>.
        /// </summary>        
        public EditorForTagHelper()
        {
        }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
                throw new ArgumentNullException(nameof(context));

            if (output == null)
                throw new ArgumentNullException(nameof(output));


            if (For != null)
            {
                TemplateValues.AddOrUpdate("htmlAttributes", HtmlAttributes.ToDictionary(e => e.Key, e => (object)e.Value));
                var control = ViewContext.GenerateEditor(For,For.Name, Template, TemplateValues);
                output.Content.AppendHtml(control);
            }
        }
    }

【讨论】:

  • 这个例子需要更新,因为 ViewContext 上不再有“GenerateEditor”方法,IDictionary 也没有 AddOrUpdate 方法。
【解决方案4】:

扩展“Prince Owusu”提供的答案,我对其进行了修改,以便“模板”属性是可选的:

[HtmlTargetElement("editor", TagStructure = TagStructure.WithoutEndTag,
    Attributes = ForAttributeName)]
public class EditorTagHelper : TagHelper
{
    private readonly IHtmlHelper _htmlHelper;

    private const string ForAttributeName = "asp-for";
    private const string TemplateAttributeName = "asp-template";

    [HtmlAttributeName(ForAttributeName)]
    public ModelExpression For { get; set; }


    [HtmlAttributeName(TemplateAttributeName)]
    public string Template { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContext { get; set; }

    public EditorTagHelper(IHtmlHelper htmlHelper)
    {
        _htmlHelper = htmlHelper;
    }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        if (output == null)
            throw new ArgumentNullException(nameof(output));

        if (!output.Attributes.ContainsName(nameof(Template)))
        {
            output.Attributes.Add(nameof(Template), Template);
        }

        output.SuppressOutput();

        (_htmlHelper as IViewContextAware).Contextualize(ViewContext);

        output.Content.SetHtmlContent(_htmlHelper.Editor(For.Name, Template));

        await Task.CompletedTask;
    }
}

这将是这样使用的:

<editor asp-for="MyModel.EmailAddress"/>

相当于:

@Html.EditorFor(x => x.MyModel.EmailAddress)

在我的使用示例中,我没有指定模板,因此 ASP.NET 将查找与我的“EmailAddress”属性类型匹配的模板。如果我想指定一个模板,我会这样使用它:

<editor asp-for="MyModel.EmailAddress" asp-template="MyEmailTemplate"/>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 2017-11-19
    • 2017-11-12
    • 2015-11-22
    • 1970-01-01
    • 2012-04-27
    • 2020-01-09
    相关资源
    最近更新 更多