将 ModelExpression 从 Tag Helper 传递到分部视图

我正在使用此处找到的示例来允许从标签助手中呈现局部视图。我在这里要做的是能够像这样定义一个标签助手:


<mydateinput for="@Model.StartDate" />

在标签助手的 c# 代码中,我定义了“for”属性,据我所知,这需要定义为“ModelExpression”。


public class MyDateInputTagHelper : TagHelper

{

    public ModelExpression For { get; set; }

    ...

}

使用本文前面提到的代码,我正在渲染一个局部视图,并简单地将标签助手的类作为局部视图的模型传递。


    public override void Process(TagHelperContext context, TagHelperOutput output)

    {

        base.Process(context, output);


        ((IViewContextAware)HtmlHelper).Contextualize(ViewContext);


        output.Content.SetHtmlContent(HtmlHelper.Partial("~/Views/Partials/TagHelpers/MyDateInput.cshtml", this));


    }

最后,我的局部视图定义如下


<input asp-for="For" />

我遇到的问题是我无法让模型表达式“For”正确传递到局部视图中。当我查看 html 源代码时,我只是在输入的 id 和名称属性中看到字面上的名称“For”。此外,在我的剃刀页面模型中设置的值也没有正确显示。


我想要发生的是 html 将以这样一种方式呈现,即在发布页面时,我的剃须刀页面的模型将填充在标签助手/部分视图下选择的值。它会特别围绕“StartDate”(在我的示例中),而不是属性“For”。


有谁知道我做错了什么,以及我可以在此示例中更改哪些内容以正确地将 ModelExpression 传递给局部视图?


手掌心
浏览 88回答 2
2回答

扬帆大鱼

直接使用 是不可能做到这一点的InputTagHelper。有关详细信息,请参阅Razor/issues #926以及关于 SO 的类似问题。解决方法但作为一种解决方法,您可以使用自定义HtmlHelper<TModel>(就像@Html)来实现相同的目标。您的部分视图可能如下所示:@model App.TagHelpers.PartialVM@{&nbsp;&nbsp; &nbsp; var PartialHtml = Model.HtmlHelper;}@PartialHtml.Label(Model.NewFor.Name,Model.NewFor.Name)&nbsp;@PartialHtml.TextBox(Model.NewFor.Name, Model.NewModel)即,使用@Html.Label()&@Html.TextBot而不是<label>& <input>。这PartialVM是一个简单的类,其中包含有关模型的元信息:public class PartialVM{&nbsp; &nbsp; public PartialVM(ModelExpression originalFor, IHtmlHelper htmlHelper)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; var originalExplorer = originalFor.ModelExplorer;&nbsp; &nbsp; &nbsp; &nbsp; OriginalFor = originalFor;&nbsp; &nbsp; &nbsp; &nbsp; OriginalExplorer = originalExplorer;&nbsp; &nbsp; &nbsp; &nbsp; NewModel = originalExplorer.Model;&nbsp; &nbsp; &nbsp; &nbsp; NewModelExplorer = originalExplorer.GetExplorerForModel(NewModel);&nbsp; &nbsp; &nbsp; &nbsp; NewFor = new ModelExpression(OriginalFor.Name, NewModelExplorer);&nbsp; &nbsp; &nbsp; &nbsp; this.HtmlHelper = htmlHelper;&nbsp; &nbsp; }&nbsp; &nbsp; public IHtmlHelper HtmlHelper { get; set; }&nbsp; &nbsp; public ModelExpression OriginalFor { get; set; }&nbsp; &nbsp; public ModelExplorer OriginalExplorer { get; set; }&nbsp; &nbsp; public ModelExpression NewFor { get; set; }&nbsp; &nbsp; public ModelExplorer NewModelExplorer { get; set; }&nbsp; &nbsp; public Object NewModel { get; set; }}请注意,IHtmlHelper实际上是 anIHtmlHelper<TSomeDynamicModel>而不是普通的IHtmlHelper。最后,将您的更改TagHelper如下:&nbsp; &nbsp; [HtmlTargetElement("my-custom-input")]&nbsp; &nbsp; public class MyCustomInputTagHelper : TagHelper&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; private readonly IServiceProvider _sp;&nbsp; &nbsp; &nbsp; &nbsp; [ViewContext]&nbsp; &nbsp; &nbsp; &nbsp; public ViewContext ViewContext { set; get; }&nbsp; &nbsp; &nbsp; &nbsp; public ModelExpression For { get; set; }&nbsp; &nbsp; &nbsp; &nbsp; public MyCustomInputTagHelper(IServiceProvider sp)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this._sp = sp;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; base.Process(context, output);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var originExplorer = For.ModelExplorer;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var newModel = originExplorer.Model;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var newExplorer = originExplorer.GetExplorerForModel(newModel);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var newFor = new ModelExpression(For.Name, newExplorer);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var ModelType = originExplorer.Container.Model.GetType();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var htmlHelperType = typeof(IHtmlHelper<>).MakeGenericType(ModelType);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var htmlHelper = this._sp.GetService(htmlHelperType) as IHtmlHelper;&nbsp; &nbsp;// get the actual IHtmlHelper<TModel>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (htmlHelper as IViewContextAware).Contextualize(ViewContext);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var vm = new PartialVM(For, htmlHelper);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var writer = new StringWriter();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var content = await htmlHelper.PartialAsync("~/Views/Partials/TagHelpers/MyDateInput.cshtml", vm);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output.TagName = "div";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output.TagMode = TagMode.StartTagAndEndTag;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; output.Content.SetHtmlContent(content);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }现在您可以为 的属性传递任何asp-for表达式字符串,它应该会按预期工作。ForTagHelper测试用例:假设我们有一个 Dto 模型:public class XModel {&nbsp; &nbsp; public int Id { get; set; }&nbsp; &nbsp; public DateTime StartDate { get; set; }&nbsp; &nbsp; public DateTime EndDate { get; set; }&nbsp; &nbsp; public string ActiveStatus{ get; set; }}您可以通过以下方式呈现它:/// the action method looks like:///&nbsp; &nbsp; var model = new XModel {///&nbsp; &nbsp; &nbsp; &nbsp; StartDate = DateTime.Now,///&nbsp; &nbsp; &nbsp; &nbsp; EndDate = DateTime.Now.AddYears(1),///&nbsp; &nbsp; &nbsp; &nbsp; ActiveStatus = "Active",///&nbsp; &nbsp; };///&nbsp; &nbsp; &nbsp;return View(model);@model XModel<my-custom-input For="StartDate" /><my-custom-input For="EndDate" /><my-custom-input For="ActiveStatus" />这是渲染时的屏幕截图:

哔哔one

或者在您的部分中使用 Html Helpers,然后它将起作用。// _MovieField.cshtml@{&nbsp; &nbsp;string propertyName = (string)ViewData["PropertyName"];}<div class="form-group">&nbsp; &nbsp;@Html.Label(propertyName, null, new{ @class = "control-label" })&nbsp; &nbsp;@Html.Editor(propertyName, new { htmlAttributes = new { @class = "form-control" } })&nbsp; &nbsp;@Html.ValidationMessage(propertyName, null, new{ @class = "text-danger" })</div>并像这样使用它// EditMovie.cshtml<form method="post">&nbsp; &nbsp;<div asp-validation-summary="ModelOnly" class="text-danger"></div>&nbsp; &nbsp;<input type="hidden" asp-for="Movie.Id" />&nbsp; &nbsp;<partial name="_MovieField" for="Movie"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; view-data='new ViewDataDictionary(ViewData){ {"PropertyName", "Title" }}' />&nbsp; &nbsp;<partial name="_MovieField" for="Movie"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; view-data='new ViewDataDictionary(ViewData){ {"PropertyName", "ReleaseDate" }}' />&nbsp; &nbsp;<partial name="_MovieField" for="Movie"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; view-data='new ViewDataDictionary(ViewData){ {"PropertyName", "Genre" }}' />&nbsp; &nbsp;<partial name="_MovieField" for="Movie"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; view-data='new ViewDataDictionary(ViewData){ {"PropertyName", "Price" }}' />&nbsp; &nbsp;<partial name="_MovieField" for="Movie"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; view-data='new ViewDataDictionary(ViewData){ {"PropertyName", "Rating" }}' />&nbsp; &nbsp;<div class="form-group">&nbsp; &nbsp; &nbsp; <input type="submit" value="Save" class="btn btn-primary" />&nbsp; &nbsp;</div></form>
打开App,查看更多内容
随时随地看视频慕课网APP