C# Can';t在MVC中定义自定义渲染器lambda
我想在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
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
作为渲染器。我传递给分部的模型包含辅助渲染的结果,即aHelperResult
。看起来是这样的:
@{
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
作为渲染器。我传递给分部的模型包含辅助渲染的结果,即aHelperResult
。看起来是这样的:
@{
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助手吗?请参见,我可以,但对于要渲染的每个不同表行,我不需要一个助手吗?我认为这些信息应该在我调用部分视图的视图中。您能详细说明一下部分视图缓存问题可能是什么吗?当然,我可以:它是