C# |无法将 'string' 转换为 'ModelExpression'
C# | Cannot convert 'string' to 'ModelExpression'
我想为表单域做一个局部视图,这样我就不用每次都写 ~10 行样板代码了。
我尝试了以下方法:
FieldViewModel.cs
using Microsoft.AspNetCore.Mvc.ViewFeatures;
public class FieldViewModel
{
public FieldViewModel(ModelExpression Data, string Label = "")
{
this.Data = Data;
this.Label = Label;
}
public ModelExpression Data { get; set; }
public string Label { get; set; }
}
_Field.cshtml(我去掉了这个例子中的 html 代码)
// ...
<input asp-for="@Model.Data" />
// ...
然后我这样称呼它:
@await Html.PartialAsync("_Field", new FieldViewModel(Model.FirstName, "First Name"))
显然,这行不通,因为我们传递了 string
而它期望 ModelExpression
。有什么办法可以工作吗?也许以某种方式手动构建 ModelExpression
(不确定如何构建)然后传递它?
我已经尝试了一些东西并且到目前为止它有效,也许还有一些边缘情况你必须考虑,还有一些你应该扩展的 TagHelpers,但基本上它看起来不错。
首先我扩展了一些标签助手,用于标签输入和跨度。
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
在以下情况下,“asp-bind”是接受 ModelExpression 并将其重新分配给“asp-for”的属性的名称属性。
[HtmlTargetElement("label", Attributes = "asp-bind")]
public class FormGroupLabelTagHelper : LabelTagHelper
{
public FormGroupLabelTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
...
[HtmlTargetElement("input", Attributes = "asp-bind")]
public class FormGroupInputTagHelper : InputTagHelper
{
public FormGroupInputTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
...
[HtmlTargetElement("span", Attributes = "asp-bind")]
public class FormGroupErrorTagHelper : ValidationMessageTagHelper
{
public FormGroupErrorTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
然后我创建了一个以 ModelExpression 作为模型的局部视图。
@model ModelExpression
<div class="form-group">
<label asp-bind="@this.Model" class="col-form-label-sm mb-0 pb-0"></label>
<input asp-bind="@this.Model" class="form-control" />
<span asp-bind="@this.Model" class="small text-danger"></span>
</div>
最后像下面这样使用
<form asp-controller="Home" asp-action="Index" method="post">
<fieldset class="card card-body m-0 p-3">
<legend class="w-auto px-1 py-0 m-0 small font-weight-bold ">With Tag Helpers</legend>
<partial name="TestGroup" model="this.ModelExpressionProvider.CreateModelExpression(this.ViewData, x => x.Name)" />
<partial name="TestGroup" model="this.ModelExpressionProvider.CreateModelExpression(this.ViewData, x => x.Age)" />
</fieldset>
<div class="d-flex mt-3">
<input type="submit" class="btn btn-primary px-5" value="Sublit" />
</div>
</form>
看起来创建的 ModelExpression 包裹在另一个 ModelExpression 中,其中 Model 是实际的 ModelExpression。我把它变成一个 ModelExpression 并将它交给 For 属性 到已经扩展的 TagHelpers.
如果你考虑走这条路,你就不再需要你的模型包装器了,你可以用下面的一些属性来装饰你的属性,而不是标签
using System.ComponentModel.DataAnnotations;
public class ExampleModel
{
[Required]
[Display(Name = "Fullname")]
public string Name { get; set; }
[Range(18, 100)]
[Display(Name = "Age")]
public int Age { get; set; }
public ExampleModel InnerModel { get; set; }
}
我想为表单域做一个局部视图,这样我就不用每次都写 ~10 行样板代码了。
我尝试了以下方法:
FieldViewModel.cs
using Microsoft.AspNetCore.Mvc.ViewFeatures;
public class FieldViewModel
{
public FieldViewModel(ModelExpression Data, string Label = "")
{
this.Data = Data;
this.Label = Label;
}
public ModelExpression Data { get; set; }
public string Label { get; set; }
}
_Field.cshtml(我去掉了这个例子中的 html 代码)
// ...
<input asp-for="@Model.Data" />
// ...
然后我这样称呼它:
@await Html.PartialAsync("_Field", new FieldViewModel(Model.FirstName, "First Name"))
显然,这行不通,因为我们传递了 string
而它期望 ModelExpression
。有什么办法可以工作吗?也许以某种方式手动构建 ModelExpression
(不确定如何构建)然后传递它?
我已经尝试了一些东西并且到目前为止它有效,也许还有一些边缘情况你必须考虑,还有一些你应该扩展的 TagHelpers,但基本上它看起来不错。
首先我扩展了一些标签助手,用于标签输入和跨度。
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Threading.Tasks;
在以下情况下,“asp-bind”是接受 ModelExpression 并将其重新分配给“asp-for”的属性的名称属性。
[HtmlTargetElement("label", Attributes = "asp-bind")]
public class FormGroupLabelTagHelper : LabelTagHelper
{
public FormGroupLabelTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
...
[HtmlTargetElement("input", Attributes = "asp-bind")]
public class FormGroupInputTagHelper : InputTagHelper
{
public FormGroupInputTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
...
[HtmlTargetElement("span", Attributes = "asp-bind")]
public class FormGroupErrorTagHelper : ValidationMessageTagHelper
{
public FormGroupErrorTagHelper(IHtmlGenerator generator)
: base(generator) { }
[HtmlAttributeName("asp-bind")]
public ModelExpression AspBind
{
get => base.For;
set => base.For = value.Model as ModelExpression;
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
=> base.ProcessAsync(context, output);
}
然后我创建了一个以 ModelExpression 作为模型的局部视图。
@model ModelExpression
<div class="form-group">
<label asp-bind="@this.Model" class="col-form-label-sm mb-0 pb-0"></label>
<input asp-bind="@this.Model" class="form-control" />
<span asp-bind="@this.Model" class="small text-danger"></span>
</div>
最后像下面这样使用
<form asp-controller="Home" asp-action="Index" method="post">
<fieldset class="card card-body m-0 p-3">
<legend class="w-auto px-1 py-0 m-0 small font-weight-bold ">With Tag Helpers</legend>
<partial name="TestGroup" model="this.ModelExpressionProvider.CreateModelExpression(this.ViewData, x => x.Name)" />
<partial name="TestGroup" model="this.ModelExpressionProvider.CreateModelExpression(this.ViewData, x => x.Age)" />
</fieldset>
<div class="d-flex mt-3">
<input type="submit" class="btn btn-primary px-5" value="Sublit" />
</div>
</form>
看起来创建的 ModelExpression 包裹在另一个 ModelExpression 中,其中 Model 是实际的 ModelExpression。我把它变成一个 ModelExpression 并将它交给 For 属性 到已经扩展的 TagHelpers.
如果你考虑走这条路,你就不再需要你的模型包装器了,你可以用下面的一些属性来装饰你的属性,而不是标签
using System.ComponentModel.DataAnnotations;
public class ExampleModel
{
[Required]
[Display(Name = "Fullname")]
public string Name { get; set; }
[Range(18, 100)]
[Display(Name = "Age")]
public int Age { get; set; }
public ExampleModel InnerModel { get; set; }
}