【问题标题】:How can I pass string value for "asp-for" in asp net 5如何在asp net 5中传递“asp-for”的字符串值
【发布时间】:2016-03-20 20:31:12
【问题描述】:

我想为一个有很多属性的实体写一个Edit.cshtml文件要编辑,所以不得不多次写如下代码:

<div class="form-group">
    <label asp-for="Email" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
</div>

其实实体很多,所以要写很多Edit.cshtml文件。我想做一些简化

我想在控制器中选择实体的一些属性并使用循环在视图中显示属性。例如: 在控制器文件中:

public IActionResult Edit(string id)
{
    var model = GetModel(id);
    var propertyNames= new List<string>()
    {
        "Name",
        "Email"
        // add some other property names of the entity 
    };
    ViewData["PropertyList"] = propertyNames;
    return View(model);
}

在视图文件中:

@{
    var propertyNames = (List<string>)ViewData["PropertyList"];
    foreach (string item in propertyNames)
    {
        <div class="form-group">
            <label asp-for="@(item)" class="col-md-2 control-label"></label>
            <div class="col-md-3">
                <input asp-for="@(item)" class="form-control" />
                <span asp-validation-for="@(item)" class="text-danger"></span>
            </div>          
        </div>
    }
}

但它不能工作,因为它会生成错误的代码。似乎我无法为“asp-for”标签助手传递字符串值。

比如我把top的代码改成这样:

@{
    string e = "Email";
    <div class="form-group">
        <label asp-for="@e" class="col-md-2 control-label"></label>
        <div class="col-md-10">
            <input asp-for="@e" class="form-control" />
            <span asp-validation-for="@e" class="text-danger"></span>
        </div>
    </div>
}

上面的代码会生成这个:

<div class="form-group">
    <label class="col-md-2 control-label" for="e">e</label>
    <div class="col-md-10">
        <input class="form-control" type="text" id="e" name="e" value="Email" />
        <span class="text-danger field-validation-valid" data-valmsg-for="e" data-valmsg-replace="true"></span>
    </div>
</div>

预期的代码是:

<div class="form-group">
    <label class="col-md-2 control-label" for="Email">Email</label>
    <div class="col-md-10">
        <input class="form-control" type="email" data-val="true" data-val-email="Email &#x5B57;&#x6BB5;&#x4E0D;&#x662F;&#x6709;&#x6548;&#x7684;&#x7535;&#x5B50;&#x90AE;&#x4EF6;&#x5730;&#x5740;&#x3002;" data-val-required="Email &#x5B57;&#x6BB5;&#x662F;&#x5FC5;&#x9700;&#x7684;&#x3002;" id="Email" name="Email" value="" />
        <span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
    </div>
</div>

我该怎么办?

剃须刀可以吗?

【问题讨论】:

  • 考虑添加“它生成错误代码”的样例。您的 CSHTML 看起来很合理。
  • 无论如何,您都需要将输入属性从“asp-for”更改为“id”
  • @AlexeiLevenkov 我添加了一个示例。

标签: c# asp.net asp.net-mvc razor tag-helpers


【解决方案1】:

你也可以试试这个:

 foreach (string item in propertyNames){
     @Html.TextBox(item, value: null, htmlAttributes: new { @class = "form-control" })      
}

【讨论】:

    【解决方案2】:

    这是一个相关的技术。我扩展了标签助手以将所需的 HTML 注入页面。这有点像 ASP.NET MVC EditorTemplate。

    这是注入特殊局部视图的自定义标签助手

    public class MyFormGroupTagHelper : PartialTagHelper
    {
        public MyFormGroupTagHelper(ICompositeViewEngine viewEngine, IViewBufferScope viewBufferScope) : base(viewEngine, viewBufferScope)
        { }
    
        public ModelExpression Property { get; set; }
    
        public string LabelText { get; set; } = null;
    
        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            this.For = Property;
            this.Name = "_FormGroup";
            // Have to use Viewdata to pass information to the partial view, because the model is the single property of the entity that will be posted back to the controller
            this.ViewData["TH_LabelText"] = LabelText;
            this.ViewData["TH_DataTypeName"] = Property.Metadata.DataTypeName;
            await base.ProcessAsync(context, output);
        }
    }
    

    这是部分视图 _FormGroup.cshtml。这将为具有 Bootstrap 样式的表单上的单个字段生成标记。如果字段是日期,它还会将“datepicker”类附加到输入标签。注意 asp-for 是如何用 @Model 填充的,所以这个相同的视图可以绑定到任何实体模型上的任何属性

    @model object
    
    @{
        string LabelText = (string)@ViewData["TH_LabelText"];
        string DataTypeName = (string) ViewData["TH_DataTypeName"];
        bool IsDate = (DataTypeName == "Date");
    }
    
    <div class="form-group row">
        @if (LabelText != null)
        {
        <label asp-for="@Model" class="control-label col-md-4">@LabelText</label>
        }
        <div class="col-md-8">
            <input asp-for="@Model" class="form-control @( IsDate ? "datepicker" : "")"  />
            <span asp-validation-for="@Model" class="text-danger"></span>
        </div>
    </div>
    

    现在在创建或编辑视图中,模型是业务实体,您可以创建代码来编辑实体上的单个属性,如下所示。

    <my-form-group label-text="Result date" property="ResultDate" view-data="ViewData" ></my-form-group>
    

    在这种情况下,模型是一个类,其中定义了一个名为 ResultDate 的字段,如下所示:

        [DataType(DataType.Date)]
        public DateTime? ResultDate { get; set; }
    

    请注意,您必须设置 view-data 属性才能将 ViewData 对象传递给标签助手。它使用 ViewData 将信息传递给局部视图。这并不理想,但我想不出任何其他方式将信息传递到局部视图。我在键前面加上“TH_”,以防止标签助手覆盖 Viewdata 中的任何其他值。

    【讨论】:

      【解决方案3】:

      好的,我设法让它工作了。 免责声明:它非常hacky,我不知道我是否以最好的方式完成了它。我所知道的是它会做你想做的事,它可能会为你指明正确的方向。

      首先,我创建了一个模型:

      using System.ComponentModel.DataAnnotations;
      
      namespace WebApplication1.Models
      {
          public class TestModel
          {
              [Required]
              public string Name { get; set; }
      
              [Required]
              [EmailAddress]
              [Display(Name = "Email Address")]
              public string Email { get; set; }
          }
      }
      

      然后,我制作了一个自定义标签助手。这是“魔术”发生的可怕之处。特别是Process方法的第一部分...

      using Microsoft.AspNet.Mvc.Rendering;
      using Microsoft.AspNet.Mvc.ViewFeatures;
      using Microsoft.AspNet.Razor.TagHelpers;
      using System.Linq;
      
      namespace WebApplication1.TagHelpers
      {
          [HtmlTargetElement("edit")]
          public class EditTagHelper : TagHelper
          {
              [HtmlAttributeName("asp-for")]
              public ModelExpression aspFor { get; set; }
      
              [ViewContext]
              [HtmlAttributeNotBound]
              public ViewContext ViewContext { get; set; }
      
              protected IHtmlGenerator _generator { get; set; }
      
              public EditTagHelper(IHtmlGenerator generator)
              {
                  _generator = generator;
              }
      
              public override void Process(TagHelperContext context, TagHelperOutput output)
              {
                  var propName = aspFor.ModelExplorer.Model.ToString();
                  var modelExProp = aspFor.ModelExplorer.Container.Properties.Single(x => x.Metadata.PropertyName.Equals(propName));
                  var propValue = modelExProp.Model;
                  var propEditFormatString = modelExProp.Metadata.EditFormatString;
      
                  var label = _generator.GenerateLabel(ViewContext, aspFor.ModelExplorer,
                      propName, propName, new { @class = "col-md-2 control-label", @type = "email" });
      
                  var input = _generator.GenerateTextBox(ViewContext, aspFor.ModelExplorer,
                      propName, propValue, propEditFormatString, new { @class = "form-control" });
      
                  var validation = _generator.GenerateValidationMessage(ViewContext, aspFor.ModelExplorer, 
                      propName, string.Empty, string.Empty, new { @class = "text-danger" });
      
                  var inputParent = new TagBuilder("div");
                  inputParent.AddCssClass("col-md-10");
                  inputParent.InnerHtml.Append(input);
                  inputParent.InnerHtml.Append(validation);
      
                  var parent = new TagBuilder("div");
                  parent.AddCssClass("form-group");
                  parent.InnerHtml.Append(label);
                  parent.InnerHtml.Append(inputParent);
      
                  output.Content.SetContent(parent);
                  base.Process(context, output);
              }
          }
      }
      

      注意:要使自定义 TagHelper 工作,您需要在 _ViewImports.cshtml 文件中添加一行,如下所示(将 WebApplication1 替换为您的命名空间):

      @addTagHelper "*, WebApplication1"
      

      我将我的操作更改为这个,以匹配您的操作(也许您可以使用反射在这里获取您的模型属性名称?):

      public IActionResult Index()
      {
          var propertyNames = new List<string>()
          {
              "Name",
              "Email"
          };
          ViewData["PropertyList"] = propertyNames;
      
          var m = new TestModel()
          {
              Name = "huoshan12345",
              Email = "test@test.net"
          };
          return View(m);
      }
      

      最后,在视图中,你可以这样做:

      <div class="row">
          @using (Html.BeginForm())
          {
              var propertyNames = (List<string>)ViewData["PropertyList"];
              foreach (string item in propertyNames)
              {
                  <edit asp-for="@item"></edit>
              }
              <input type="submit" value="Submit" />
          }
      </div>
      

      【讨论】:

      • 哇。非常感谢。实际上,您还回答了另一个令我困惑的关于 taghelper 的问题。 ----stackoverflow.com/questions/33649181/…
      • 您的回答引导了我的回答。会参考这个答案。
      • 在 ASP.NET Core 2 中不起作用。 GenerateValidationMessage 需要 6 个参数,第二个参数必须是 ModelExplorer 类型。如何将 ModelExplorer 传递给方法?
      【解决方案4】:

      是的,可以用剃刀写。 认为这会对你有所帮助。如果您不放置“类型”属性,它将使用type='text' 生成它。您也可以对 data-val 属性进行硬编码,但不建议将 '-' 替换为 '_' 例如:@data_val_email

      <div class="form-group">
        @Html.LabelFor(x=>x.Email)
        <div class="col-md-10">
           @Html.TextBoxFor(x => x.Email, new { @class = "form-control", @type = "email" })
            @Html.ValidateFor(x=>x.Email)
        </div>
      </div>
      

      【讨论】:

      • 如果我忘了什么你可以给我写评论
      • 其实我已经试过了。我将所有属性名称转换为 LambdaExpression 列表,并将它们中的每一个传递给诸如“Html.LabelFor”之类的方法。但是它也不起作用,因为无法从用法中推断出方法的类型参数,并且会引发异常。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 2016-12-16
      • 1970-01-01
      相关资源
      最近更新 更多