2013-03-12 86 views
1

我想在自己的MVC視圖中將自定義渲染器定義爲lambda,我可以在局部使用它來多次渲染相同的東西。我打算將它存儲在視圖數據中。到目前爲止,我已經創建了此擴展方法來存儲渲染器:無法在MVC中定義自定義渲染器lambda

public static class HtmlHelperExtensions 
{ 
    public static void DefineRenderer<TModel>(this HtmlHelper<TModel> html, string rendererName, Action renderer) 
    { 
     html.ViewData["_Renderer" + rendererName] = renderer; 
    } 
} 

我試圖在我的視圖中定義渲染器,但它不工作;我假設我的語法關閉。有人能告訴我我在這裏做錯了嗎?我只是希望它渲染測試段調用時:

@Html.DefineRenderer("AnalysisTableHeader",() => { 
    <p>test paragraph</p> 
@}); 
+0

究竟要達到什麼目的? @helper對你來說不夠嗎? – mariozski 2013-03-12 13:47:33

+1

你期望助手做什麼?哦,使用'ViewBag'而不是'ViewData',這是一個更好的做法。 ;) – ecampver 2013-03-12 13:58:46

+0

@ e.campver其實我認爲恰恰相反。我儘可能避開動態。我喜歡我的語言強烈類型。 – Jez 2013-03-12 14:45:07

回答

0

從@ mariozski的評論中得到一些啓發,我設法得到了我想要工作的行爲。我使用@helper作爲渲染器。我傳遞給partial的模型包含輔助渲染的結果,即。一個HelperResult。所以它看起來像這樣:

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 
} 
1

DefineRenderer - 方法需要返回以外的任何空隙,如其他IHtmlString與剃刀@ -syntax調用它,否則你將需要調用它像這樣:

@{ 
    Html.DefineRenderer("AnalysisTableHeader",() => { 
     <p>test paragraph</p> 
    }); 
} 

編輯:對不起,我已經看到了renderer參數是System.Action類型。我想這一定是System.Func<dynamic, HelperResult>類型的,你需要把它

@{ Html.DefineRenderer("AnalysisTableHeader", @<text><p>test paragraph</p></text>); } 

例如。然後你可以像這樣渲染它:render(null).ToHtmlString()。無論如何要注意,如果你在視圖中做這樣的事情,你可能會遇到局部視圖緩存問題。

+0

您能詳細介紹一下部分視圖緩存問題嗎? – Jez 2013-03-12 14:46:04

+0

因爲我可以:這是關於當前呈現的內容和不是。假設你改變了''DefineRenderer''方法的簽名,使得它返回''IHtmlString''(MvcHtmlString.Empty)並且你調用''@ Html.DefineRenderer(「x」,...)''in你的看法。在使用OutputCacheAttribute時,系統將生成的Html標記保存到緩存中(在這種情況下爲空字符串),稍後不會調用「DefineRenderer」方法,因爲它服務於緩存的結果。只要您嘗試訪問渲染器,就會失敗,因爲它從未放入ViewDataDictionary中。 – Peit 2013-03-12 14:50:21

+0

那麼在這種情況下達到我想要的最佳方式是什麼? – Jez 2013-03-12 14:53:04

0

我仍然不是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) 

或者你可以根據字符串值或別的東西做切換。

+0

有沒有辦法將幫助器方法傳遞到局部視圖中,這樣我的局部可以調用類似於'RenderHeaderRow()'的東西,並且每個使用該局部的視圖都必須定義一個名爲'RenderHeaderRow'的幫助器? – Jez 2013-03-12 15:13:57

+1

您可以在視圖中做這樣的事情:@ Html.Partial(「PartialName」,new {renderer = RenderCustom(HeaderTypes.AnalysisTable)})以及部分:@ Model.renderer。這對你來說足夠了嗎?爲什麼不在部分本身中定義助手? :) – mariozski 2013-03-12 15:32:51

+0

因爲在語義上我認爲定義在父視圖本身的父視圖中不同的標記是有意義的。但是,你的建議似乎已經奏效。我現在正在開發它,並可能會提出解決方案的答案,並進行細化。 – Jez 2013-03-12 15:46:59