C# Can';t在MVC中定义自定义渲染器lambda

C# Can';t在MVC中定义自定义渲染器lambda,c#,asp.net-mvc,razor,C#,Asp.net Mvc,Razor,我想在MVC视图中将自定义渲染器定义为lambda,这样我就可以在局部视图中使用它多次渲染同一事物。我计划将其存储在视图数据中。到目前为止,我已经创建了此扩展方法来存储渲染器: public static class HtmlHelperExtensions { public static void DefineRenderer<TModel>(this HtmlHelper<TModel> html, string rendererName, Action ren

我想在MVC视图中将自定义渲染器定义为lambda,这样我就可以在局部视图中使用它多次渲染同一事物。我计划将其存储在视图数据中。到目前为止,我已经创建了此扩展方法来存储渲染器:

public static class HtmlHelperExtensions
{
   public static void DefineRenderer<TModel>(this HtmlHelper<TModel> html, string rendererName, Action renderer)
   {
      html.ViewData["_Renderer" + rendererName] = renderer;
   }
}
公共静态类HtmlHelperExtensions
{
公共静态void DefineRenderer(此HtmlHelper html、字符串呈现器名称、动作呈现器)
{
ViewData[“_Renderer”+rendererName]=渲染器;
}
}
我试图在视图中定义渲染器,但它不起作用;我想我的语法是错的。谁能告诉我我做错了什么?我只想让它在调用时呈现测试段落:

@Html.DefineRenderer("AnalysisTableHeader", () => {
    <p>test paragraph</p>
@});
@Html.DefineRenderer(“AnalysisTableHeader”,()=>{
测试段

@});
definerender
-方法需要返回除void以外的任何内容,例如
IHtmlString
以使用razor
@
-语法调用它,否则您需要这样调用它:

@{
    Html.DefineRenderer("AnalysisTableHeader", () => {
        <p>test paragraph</p>
    });
}
public class AnalysisResponseTableViewModel {
    public HelperResult HeaderTypeRowRenderer { get; set; }
    public List<AnalysisUserResponseViewModel> Responses { get; set; }
}
@helper RenderHeaderTypeRow() {
    <tr class="headerTypeRow">
        <td>Header type row</td>
        <td>Goes here</td>
    </tr>
}

@Html.Partial("AnalysisResponseTableContentsPartial",
    new AnalysisResponseTableViewModel {
        Responses = Model.OverallCaseStudyUserResponses,
        HeaderTypeRowRenderer = RenderHeaderTypeRow()
    }
)
@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
@{bool reachedSummaryRows = false;}
@foreach (var response in Model.Responses) {
    if (!reachedSummaryRows && !response.IsPass.HasValue) {
        reachedSummaryRows = true;
        @:@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
    }

    // other table rows here
}

比如说。然后,您可以像这样渲染它:
render(null).ToHtmlString()
。无论如何,请注意,如果在视图中执行类似操作,您可能会遇到部分视图缓存问题。

DefineRenderer-方法需要返回除void以外的任何内容,例如
IHtmlString
以使用razor
@
-语法调用它,否则您需要这样调用它:

@{
    Html.DefineRenderer("AnalysisTableHeader", () => {
        <p>test paragraph</p>
    });
}
public class AnalysisResponseTableViewModel {
    public HelperResult HeaderTypeRowRenderer { get; set; }
    public List<AnalysisUserResponseViewModel> Responses { get; set; }
}
@helper RenderHeaderTypeRow() {
    <tr class="headerTypeRow">
        <td>Header type row</td>
        <td>Goes here</td>
    </tr>
}

@Html.Partial("AnalysisResponseTableContentsPartial",
    new AnalysisResponseTableViewModel {
        Responses = Model.OverallCaseStudyUserResponses,
        HeaderTypeRowRenderer = RenderHeaderTypeRow()
    }
)
@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
@{bool reachedSummaryRows = false;}
@foreach (var response in Model.Responses) {
    if (!reachedSummaryRows && !response.IsPass.HasValue) {
        reachedSummaryRows = true;
        @:@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
    }

    // other table rows here
}

比如说。然后,您可以像这样渲染它:
render(null).ToHtmlString()
。无论如何,请注意,如果在视图中执行类似操作,您可能会遇到部分视图缓存问题。

我仍然无法100%确定这是否是您所需要的,但可能会有所帮助。 在局部视图中定义@helper,并根据模型中的值决定渲染哪个版本:

在代码中声明带有头类型的枚举

public enum HeaderTypes
{
    AnalysisTable,
    SomethingElse
}
那么在你看来,

@helper RenderHeader(HeaderTypes headerType) {
    switch (headerType)
    {
        case HeaderTypes.AnalysisTable:
            @: <p>your html</p>
            break;
        default: 
            @: <p>default</p>
            break;
    }
}

@RenderHeader(HeaderTypes.None)
@RenderHeader(HeaderTypes.AnalysisTable)
@helper呈现阅读器(HeaderTypes headerType){
开关(头型)
{
案例标题Types.AnalysisTable:
@:你的html

打破 违约: @:默认值

打破 } } @RenderHeader(HeaderTypes.None) @RenderHeader(HeaderTypes.AnalysisTable)

或者您可以根据字符串值或其他内容进行切换。

我仍然不能100%确定这是否是您需要的,但可能会有所帮助。 在局部视图中定义@helper,并根据模型中的值决定渲染哪个版本:

在代码中声明带有头类型的枚举

public enum HeaderTypes
{
    AnalysisTable,
    SomethingElse
}
那么在你看来,

@helper RenderHeader(HeaderTypes headerType) {
    switch (headerType)
    {
        case HeaderTypes.AnalysisTable:
            @: <p>your html</p>
            break;
        default: 
            @: <p>default</p>
            break;
    }
}

@RenderHeader(HeaderTypes.None)
@RenderHeader(HeaderTypes.AnalysisTable)
@helper呈现阅读器(HeaderTypes headerType){
开关(头型)
{
案例标题Types.AnalysisTable:
@:你的html

打破 违约: @:默认值

打破 } } @RenderHeader(HeaderTypes.None) @RenderHeader(HeaderTypes.AnalysisTable)

或者,您可以根据字符串值或其他内容进行切换。

从@mariozski的评论中获得了一些灵感,我成功地获得了我想要的行为。我使用
@helper
作为渲染器。我传递给分部的模型包含辅助渲染的结果,即a
HelperResult
。看起来是这样的:

@{
    Html.DefineRenderer("AnalysisTableHeader", () => {
        <p>test paragraph</p>
    });
}
public class AnalysisResponseTableViewModel {
    public HelperResult HeaderTypeRowRenderer { get; set; }
    public List<AnalysisUserResponseViewModel> Responses { get; set; }
}
@helper RenderHeaderTypeRow() {
    <tr class="headerTypeRow">
        <td>Header type row</td>
        <td>Goes here</td>
    </tr>
}

@Html.Partial("AnalysisResponseTableContentsPartial",
    new AnalysisResponseTableViewModel {
        Responses = Model.OverallCaseStudyUserResponses,
        HeaderTypeRowRenderer = RenderHeaderTypeRow()
    }
)
@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
@{bool reachedSummaryRows = false;}
@foreach (var response in Model.Responses) {
    if (!reachedSummaryRows && !response.IsPass.HasValue) {
        reachedSummaryRows = true;
        @:@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
    }

    // other table rows here
}

从@mariozski的评论中得到了一些灵感,我成功地获得了我想要的行为。我使用
@helper
作为渲染器。我传递给分部的模型包含辅助渲染的结果,即a
HelperResult
。看起来是这样的:

@{
    Html.DefineRenderer("AnalysisTableHeader", () => {
        <p>test paragraph</p>
    });
}
public class AnalysisResponseTableViewModel {
    public HelperResult HeaderTypeRowRenderer { get; set; }
    public List<AnalysisUserResponseViewModel> Responses { get; set; }
}
@helper RenderHeaderTypeRow() {
    <tr class="headerTypeRow">
        <td>Header type row</td>
        <td>Goes here</td>
    </tr>
}

@Html.Partial("AnalysisResponseTableContentsPartial",
    new AnalysisResponseTableViewModel {
        Responses = Model.OverallCaseStudyUserResponses,
        HeaderTypeRowRenderer = RenderHeaderTypeRow()
    }
)
@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
@{bool reachedSummaryRows = false;}
@foreach (var response in Model.Responses) {
    if (!reachedSummaryRows && !response.IsPass.HasValue) {
        reachedSummaryRows = true;
        @:@Html.Raw(Model.HeaderTypeRowRenderer.ToHtmlString())
    }

    // other table rows here
}


你到底想达到什么目的@帮手对你来说是不够的?你希望你的帮手做什么?哦,使用
ViewBag
而不是
ViewData
,这是一种更好的做法@e、 事实上,我认为恰恰相反。只要有可能,我就会避开动态。我喜欢我的强类型语言。@mariozski我有一个局部视图,可以呈现一个表。我希望调用代码能够指示如何呈现“header”行,因为它需要呈现两次。@Jez它仍然是硬类型的,但是动态的。:-)鸭子打字之类的事情还是不可能的。到底想达到什么目的@帮手对你来说是不够的?你希望你的帮手做什么?哦,使用
ViewBag
而不是
ViewData
,这是一种更好的做法@e、 事实上,我认为恰恰相反。只要有可能,我就会避开动态。我喜欢我的强类型语言。@mariozski我有一个局部视图,可以呈现一个表。我希望调用代码能够指示如何呈现“header”行,因为它需要呈现两次。@Jez它仍然是硬类型的,但是动态的。:-)Duck类型和其他东西仍然是不可能的。你能详细说明一下部分视图缓存问题可能是什么吗?当然,我可以:这是关于当前渲染的内容和未渲染的内容。假设您更改
DefineRenderer
-方法的签名,使其返回
IHtmlString
(MvcHtmlString.Empty),并在视图中调用
@Html.DefineRenderer(“x”,…)
。在您使用
OutputCacheAttribute
时,系统将生成的Html标记保存到缓存中(本例中为空字符串),并且稍后不会调用
DefineRenderer
方法,因为它提供缓存结果。一旦您尝试访问渲染器,就会失败,因为它从未被放入ViewDataDictionary。那么,在这种情况下,实现我想要的效果的最佳方式是什么?@Jez这取决于您尝试实现的效果。我认为您应该始终在需要的地方呈现标记,以避免出现问题和困难。你不能改用html助手吗?请参见,我可以,但对于要渲染的每个不同表行,我不需要一个助手吗?我认为这些信息应该在我调用部分视图的视图中。您能详细说明一下部分视图缓存问题可能是什么吗?当然,我可以:它是