将ModelExpression从标签助手传递到局部视图

时间:2019-03-31 23:40:46

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

我正在使用示例found here来允许从标记帮助器中呈现部分视图。我要在这里要做的是能够像这样定义一个标记助手:

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

在标记帮助器的c#代码中,我将定义“ for”属性,据我所知,这需要定义为“ ModelExpression”。

public class MyDateInputTagHelper : TagHelper
{
    public ModelExpression For { get; set; }
    ...
}

使用this article中前面提到的代码,我正在渲染部分视图,并简单地将标记帮助器的类作为部分视图的模型传递。

    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和name属性中实际看到名称“ For”。另外,在我的剃刀页面模型中设置的值也无法正确显示。

我想发生的是,将以这样一种方式呈现html:在发布页面时,将使用在标签helper / partial view下选择的值填充到我的剃刀页面的模型。具体来说,它将位于“ StartDate”(在我的示例中)周围,而不是属性“ For”。

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

1 个答案:

答案 0 :(得分:1)

不可能直接使用InputTagHelper来做到这一点。有关更多信息,请参见Razor/issues #926a similar question on SO

Walkaournd

但是,作为一种解决方法,您可以使用自定义的HtmlHelper<TModel>(就像@Html一样)。您的局部视图可能如下所示:

@model App.TagHelpers.PartialVM

@{ 
    var PartialHtml = Model.HtmlHelper;
}

@PartialHtml.Label(Model.NewFor.Name,Model.NewFor.Name) 
@PartialHtml.TextBox(Model.NewFor.Name, Model.NewModel)

即,使用@Html.Label()@Html.TextBot而不是<label><input>

PartialVM是一个简单的类,其中包含有关模型的元信息:

public class PartialVM
{

    public PartialVM(ModelExpression originalFor, IHtmlHelper htmlHelper)
    {
        var originalExplorer = originalFor.ModelExplorer;

        OriginalFor = originalFor;
        OriginalExplorer = originalExplorer;
        NewModel = originalExplorer.Model;
        NewModelExplorer = originalExplorer.GetExplorerForModel(NewModel);
        NewFor = new ModelExpression(OriginalFor.Name, NewModelExplorer);
        this.HtmlHelper = htmlHelper;
    }


    public IHtmlHelper HtmlHelper { get; set; }

    public ModelExpression OriginalFor { get; set; }
    public ModelExplorer OriginalExplorer { get; set; }
    public ModelExpression NewFor { get; set; }
    public ModelExplorer NewModelExplorer { get; set; }
    public Object NewModel { get; set; }
}

请注意,IHtmlHelper实际上是 IHtmlHelper<TSomeDynamicModel>而不是普通的IHtmlHelper

最后,如下更改您的TagHelper

    [HtmlTargetElement("my-custom-input")]
    public class MyCustomInputTagHelper : TagHelper
    {
        private readonly IServiceProvider _sp;

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

        public ModelExpression For { get; set; }

        public MyCustomInputTagHelper(IServiceProvider sp)
        {
            this._sp = sp;
        }

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            base.Process(context, output);

            var originExplorer = For.ModelExplorer;
            var newModel = originExplorer.Model;
            var newExplorer = originExplorer.GetExplorerForModel(newModel);
            var newFor = new ModelExpression(For.Name, newExplorer);
            var ModelType = originExplorer.Container.Model.GetType();

            var htmlHelperType = typeof(IHtmlHelper<>).MakeGenericType(ModelType);
            var htmlHelper = this._sp.GetService(htmlHelperType) as IHtmlHelper;   // get the actual IHtmlHelper<TModel>
            (htmlHelper as IViewContextAware).Contextualize(ViewContext);

            var vm = new PartialVM(For, htmlHelper);

            var writer = new StringWriter();
            var content = await htmlHelper.PartialAsync("~/Views/Partials/TagHelpers/MyDateInput.cshtml", vm);
            output.TagName = "div";
            output.TagMode = TagMode.StartTagAndEndTag;
            output.Content.SetHtmlContent(content);
        }
    }

现在,您可以为asp-for的{​​{1}}属性传递任何For表达式字符串,并且应该可以正常工作。

测试用例:

假设我们有一个Dto模型:

TagHelper

您可以通过以下方式呈现它:

public class XModel {
    public int Id { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public string ActiveStatus{ get; set; }
}

以下是渲染时的屏幕截图:

enter image description here