如何在 asp net 5 中传递 "asp-for" 的字符串值
How can I pass string value for "asp-for" in asp net 5
我想为一个实体写一个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个文件。我想做一些简化
我想 select 控制器中实体的一些属性,并使用循环在视图中显示属性。例如:
在控制器文件中:
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 字段不是有效的电子邮件地址。" data-val-required="Email 字段是必需的。" id="Email" name="Email" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
</div>
</div>
我该怎么办?
剃须刀可以吗?
是的,可以用razor来写。
认为这会帮助你。如果您不放置 "type" 属性,它将使用 type='text'
生成它。您也可以对数据值属性进行硬编码,但不建议将“-”替换为“_”,例如:@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>
好的,我设法让它工作了。 免责声明: 这太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; }
}
}
然后,我制作了一个自定义标签助手。这是 "magic" 发生的可怕之处。特别是 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>
这里有一个相关的技巧。我扩展了标签助手以将所需的 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" class 附加到输入标签。请注意 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>
在这种情况下,模型是一个 class,其中包含一个名为 ResultDate 的字段,定义如下:
[DataType(DataType.Date)]
public DateTime? ResultDate { get; set; }
请注意,您必须设置 view-data 属性才能将 ViewData 对象传递到标签助手中。它使用 ViewData 将信息传递给局部视图。这并不理想,但我想不出任何其他方式将信息传递给局部视图。我在键前加上 "TH_" 以防止标签助手覆盖 Viewdata 中的任何其他值。
你也可以试试这个:
foreach (string item in propertyNames){
@Html.TextBox(item, value: null, htmlAttributes: new { @class = "form-control" })
}
我想为一个实体写一个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个文件。我想做一些简化
我想 select 控制器中实体的一些属性,并使用循环在视图中显示属性。例如: 在控制器文件中:
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 字段不是有效的电子邮件地址。" data-val-required="Email 字段是必需的。" id="Email" name="Email" value="" />
<span class="text-danger field-validation-valid" data-valmsg-for="Email" data-valmsg-replace="true"></span>
</div>
</div>
我该怎么办?
剃须刀可以吗?
是的,可以用razor来写。
认为这会帮助你。如果您不放置 "type" 属性,它将使用 type='text'
生成它。您也可以对数据值属性进行硬编码,但不建议将“-”替换为“_”,例如:@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>
好的,我设法让它工作了。 免责声明: 这太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; }
}
}
然后,我制作了一个自定义标签助手。这是 "magic" 发生的可怕之处。特别是 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>
这里有一个相关的技巧。我扩展了标签助手以将所需的 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" class 附加到输入标签。请注意 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>
在这种情况下,模型是一个 class,其中包含一个名为 ResultDate 的字段,定义如下:
[DataType(DataType.Date)]
public DateTime? ResultDate { get; set; }
请注意,您必须设置 view-data 属性才能将 ViewData 对象传递到标签助手中。它使用 ViewData 将信息传递给局部视图。这并不理想,但我想不出任何其他方式将信息传递给局部视图。我在键前加上 "TH_" 以防止标签助手覆盖 Viewdata 中的任何其他值。
你也可以试试这个:
foreach (string item in propertyNames){
@Html.TextBox(item, value: null, htmlAttributes: new { @class = "form-control" })
}