Razor 复杂自定义标记辅助程序

Razor 复杂自定义标记辅助程序,razor,asp.net-core,tag-helpers,Razor,Asp.net Core,Tag Helpers,基本上,我扩展了前面回答的问题(),因此它是一个自定义标记帮助器 我想向自定义标记助手发送一个与用户相关的电话列表,并为每个电话生成一个文本框 因此,假设我有以下语法: <user-phones phones="@Model.UserPhones" /> 再次感谢你的帮助。。。仍在学习asp.net核心。您就快到了 设计 这里的困难在于我们需要为未知属性构造一个表达式。假设您想在更高的级别上使用,请考虑以下代码: @model M0 @{ var M1 = GetM1By

基本上,我扩展了前面回答的问题(),因此它是一个自定义标记帮助器

我想向自定义标记助手发送一个与用户相关的电话列表,并为每个电话生成一个文本框

因此,假设我有以下语法:

<user-phones phones="@Model.UserPhones" />
再次感谢你的帮助。。。仍在学习asp.net核心。

您就快到了

设计

这里的困难在于我们需要为未知属性构造一个表达式。假设您想在更高的级别上使用
,请考虑以下代码:

@model M0

@{
    var M1 = GetM1ByMagic(M0);
}
<user-phones asp-for="@M1.M2....Mx.UserPhones">
</user-phones>
ExpressionFilter
这里是一个转换表达式字符串的简单委托

显示代码

我只是复制了您的大部分代码并做了一些更改:

public class UserPhonesTagHelper : TagHelper
{
    private readonly IHtmlGenerator _htmlGenerator;
    private const string ForAttributeName = "asp-for";


    public IList<UserPhones> Phones { get; set; }

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

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

    public UserPhonesTagHelper(IHtmlGenerator htmlGenerator)
    {
        _htmlGenerator = htmlGenerator;
    }

    [HtmlAttributeName("expression-filter")]
    public Func<string, string> ExpressionFilter { get; set; } = e => e;

    // a helper method that generate a label and input for some property
    private TagBuilder GenerateSimpleInputForField( int index ,PropertyInfo pi)
    {
        var instance = Phones[index];// current instance of a single UserPhone
        var name = pi.Name;          // property name : e.g. "PhoneNumberId"
        var v = pi.GetValue(instance);

        var div = new TagBuilder("div");
        div.AddCssClass("form-group");

        var expression = this.ExpressionFilter(For.Name + $"[{index}].{name}");
        var explorer = For.ModelExplorer.GetExplorerForExpression(typeof(IList<UserPhones>), o =>v);

        var label = _htmlGenerator.GenerateLabel( ViewContext, explorer, expression, name, new { } );
        div.InnerHtml.AppendHtml(label);

        var input = _htmlGenerator.GenerateTextBox( ViewContext, explorer, expression, v, null, new { @class = "form-control" } );
        div.InnerHtml.AppendHtml(input);
        return div;
    }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "div";
        output.TagMode = TagMode.StartTagAndEndTag;

        var type = typeof(UserPhones);
        PropertyInfo phoneId= type.GetProperty("UserPhoneId");
        PropertyInfo phoneNumber= type.GetProperty("PhoneNumber");

        for (int i = 0; i< Phones.Count();i++) {
            var div1 = this.GenerateSimpleInputForField(i,phoneId);
            var div2 = this.GenerateSimpleInputForField(i,phoneNumber);

            output.Content.AppendHtml(div1);
            output.Content.AppendHtml(div2);
        }
    }
}
  • 某些字段的默认表达式字符串由以下内容生成:

    get_the_name_by('asp-for') +'[<index>]'+'<property-name>'  
    
  • 测试用例

    <div class="row">
        @await Html.PartialAsync("_NameAndID", Model.AppUser)
    </div>
    
    <form method="post">
        <div class="row">
            <user-phones phones="@Model.AppUser.UserPhones" asp-for="@Model.AppUser.UserPhones" expression-filter="e => e.Substring(8)"></user-phones>
        </div>
    
        <button type="submit">submit</button>
    </form>
    
    
    @等待Html.partialSync(“\u NameAndID”,Model.AppUser)
    提交
    
    第一部分由局部视图生成,第二部分由用户电话生成:


    先生,您真是太棒了!谢谢你在这方面的帮助!我一点也不懂表达式过滤器的内容,但它确实起作用了:)好吧,@itness在这一系列问题中,我有一个最后的问题,我想你可能会愿意帮忙。再次感谢你的帮助。如果不是,也不用担心!见:
    public class UserPhonesTagHelper : TagHelper
    {
        private readonly IHtmlGenerator _htmlGenerator;
        private const string ForAttributeName = "asp-for";
    
    
        public IList<UserPhones> Phones { get; set; }
    
        [ViewContext]
        public ViewContext ViewContext { set; get; }
    
        [HtmlAttributeName(ForAttributeName)]
        public ModelExpression For { get; set; }
    
        public UserPhonesTagHelper(IHtmlGenerator htmlGenerator)
        {
            _htmlGenerator = htmlGenerator;
        }
    
        [HtmlAttributeName("expression-filter")]
        public Func<string, string> ExpressionFilter { get; set; } = e => e;
    
        // a helper method that generate a label and input for some property
        private TagBuilder GenerateSimpleInputForField( int index ,PropertyInfo pi)
        {
            var instance = Phones[index];// current instance of a single UserPhone
            var name = pi.Name;          // property name : e.g. "PhoneNumberId"
            var v = pi.GetValue(instance);
    
            var div = new TagBuilder("div");
            div.AddCssClass("form-group");
    
            var expression = this.ExpressionFilter(For.Name + $"[{index}].{name}");
            var explorer = For.ModelExplorer.GetExplorerForExpression(typeof(IList<UserPhones>), o =>v);
    
            var label = _htmlGenerator.GenerateLabel( ViewContext, explorer, expression, name, new { } );
            div.InnerHtml.AppendHtml(label);
    
            var input = _htmlGenerator.GenerateTextBox( ViewContext, explorer, expression, v, null, new { @class = "form-control" } );
            div.InnerHtml.AppendHtml(input);
            return div;
        }
    
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            output.TagMode = TagMode.StartTagAndEndTag;
    
            var type = typeof(UserPhones);
            PropertyInfo phoneId= type.GetProperty("UserPhoneId");
            PropertyInfo phoneNumber= type.GetProperty("PhoneNumber");
    
            for (int i = 0; i< Phones.Count();i++) {
                var div1 = this.GenerateSimpleInputForField(i,phoneId);
                var div2 = this.GenerateSimpleInputForField(i,phoneNumber);
    
                output.Content.AppendHtml(div1);
                output.Content.AppendHtml(div2);
            }
        }
    }
    
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = "div";
        output.TagMode = TagMode.StartTagAndEndTag;
    
        for (int i = 0; i < Phones.Count(); i++)
        {
            var pis = typeof(UserPhones).GetProperties();
            foreach (var pi in pis)
            {
                var div = this.GenerateSimpleInputForField(i, pi);
                output.Content.AppendHtml(div);
            }
        }
    }
    
    get_the_name_by('asp-for') +'[<index>]'+'<property-name>'  
    
    // use <user-phones> in view file :
    
    // custom our own expression filter :
    @{
        var regex= new System.Text.RegularExpressions.Regex(@"...");
    
        Func<string, string> expressionFilter = e => {
            var m = regex.Match(e);
            // ...
            return m.Groups["expression"].Value;
        };
    }
    <user-phones phones="@Model.AppUser.UserPhones" 
        asp-for="@Model.AppUser.UserPhones" 
        expression-filter="expressionFilter">
    </user-phones>
    
    <div class="row">
        @await Html.PartialAsync("_NameAndID", Model.AppUser)
    </div>
    
    <form method="post">
        <div class="row">
            <user-phones phones="@Model.AppUser.UserPhones" asp-for="@Model.AppUser.UserPhones" expression-filter="e => e.Substring(8)"></user-phones>
        </div>
    
        <button type="submit">submit</button>
    </form>