2012-01-31 84 views
10

我甚至不確定這是否可能,但我想我會檢查是否有任何方法可以使這更容易。MVC 3剃刀,助手與自定義標記/部分

首先,我在我的網站一些重複的標記,看起來像這樣:

<div class="module"> 
    <h3>Title</h3> 
    <div> 
     <p>Information goes here</p> 
    </div> 
</div> 

我想要做的是在某種幫手/段的包這件事,這樣我可以做這樣的事情

@MyHelper("This is my Title") { 
    <p>Here is my custom markup</p> 
} 

然後,當它呈現,它會通過注入的<h3></h3>,並在申報單的自定義標記之間的參數傳遞的稱號。自定義標記可以是測試,形成控件或局部視圖。這是可能的嗎?

回答

12

好吧,這裏有一個「標準」的方式來做一些接近它的事情,使用HTML助手擴展。 Html.BeginForm()所做的一個非常簡單的版本。

方法:只需返回一個IDisposable,然後讓其餘的using聲明處理。

這只是一個概念的例子(雖然它有效)。不打算立即重用。快速寫入很多快捷方式,而不是生產代碼,很多改進和優化的機會,可能會有愚蠢的錯誤,可以使用TagBuilder等等。可以很容易地修改以重用Wrapper類用於不同的...包裝(甚至可能在ASP.NET MVC中已經是通用的了 - 不需要一個)。

public static class WrapHelper 
{ 
    private class Wrapper : IDisposable 
    { 
     private bool disposed; 
     private readonly TextWriter writer; 

     public Wrapper(HtmlHelper html) 
     { 
      this.writer = html.ViewContext.Writer; 
     } 

     public void Dispose() 
     { 
      if (disposed) return; 

      disposed = true; 

      writer.WriteLine(" </div>"); 
      writer.WriteLine("</div>"); 
     } 
    } 

    public static IDisposable Wrap(this HtmlHelper html, string title) 
    { 
     TextWriter writer = html.ViewContext.Writer; 

     writer.WriteLine("<div class=\"module\">"); 
     writer.WriteLine(" <h3>" + html.Encode(title) + "</h3>"); 
     writer.WriteLine(" <div>"); 

     return new Wrapper(html); 
    } 
} 

用法:

@using (Html.Wrap("Title")) 
{ 
    <p>My very own markup.</p> 
} 
+0

這正是我一直在尋找的。 – Josh 2012-02-01 14:02:10

+0

有一個簡單的例子在http://stackoverflow.com/questions/7196276/creating-mvc3-razor-helper-like-helper-beginform – 2013-03-07 11:14:27

+0

我很難看到是什麼使它更簡單,考慮到解決方案正是相同......在這個例子中,唯一的附加代碼就是爲了滿足問題的要求 - 還有一個基本的檢查,以避免Dispose的副作用被兩次調用。 – JimmiTh 2013-03-07 12:07:50

0

如果您使用的剃刀和MVC 3它的真正容易編寫會去App_Code文件夾內的一個快速的輔助方法,(我將其命名爲MyHtmlHelpers)

我想嘗試的東西有點不同,更容易一些,如:

@helper myTemplate(string title, string markup){ 
    <div class="module"> 
     <h3>@title</h3> 
     @markup 
    </div> 
} 

而且你的U方式它從一個.cshtml文件如下:

@MyHtmlHelpers.myTemplate('title','markup') 

它應該工作,如果我正確理解你。

+1

我不希望標記是一個字符串參數,因爲我想在我的視圖中將標記作爲常規html。我想要做的就是在MVC 3中使用一個助手模仿MVC 2中的內容,您可以使用<%使用(Html.Beginform()){%> html標記<% } %>' – Josh 2012-02-01 14:00:28

3

@TheKaneda,謝謝你的見解。我把你的想法和擴展它,這樣你就提供了一個PartialView名稱,它知道如何解析它。

<Extension()> _ 
Public Function UseTemplate(ByVal html As HtmlHelper, ByVal PartialView As String) As IDisposable 
    Return New TemplateWrapper(html, PartialView) 
End Function 

Public Class TemplateWrapper 
    Implements IDisposable 

    Private _HtmlHelper As HtmlHelper 

    'Index 0 is header 
    'Index 1 is footer 
    Private _TemplateWrapper As String() 

    Public Sub New(ByVal Html As HtmlHelper, ByVal PartialView As String) 

     _TemplateWrapper = Html.Partial(PartialView).ToHtmlString.Split("@@RenderBody()") 

     _HtmlHelper = Html 
     _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(0)) 

    End Sub 

    Public Sub Dispose() Implements IDisposable.Dispose 

     _HtmlHelper.ViewContext.Writer.Write(_TemplateWrapper(1).Substring(12)) 

    End Sub 

End Class 

使用與@ TheKaneda示例相同的用法。在你的局部視圖中,不要調用@RenderBody(),只需將@@ RenderBody()作爲內容中間部分的標誌。對不起VB翻譯。

使用我的用法的一個例子。

Using Html.UseTemplate("ContentWrapper") 

    @Html.EditorFor(Function(m) m.Var1, "TemplateHint") 
    @Html.EditorFor(Function(m) m.Var2, "TemplateHint") 
    @Html.EditorFor(Function(m) m.Var3) 

End Using 

我的部分看起來像這樣...

<div class="content"> 
    @@RenderBody() 
</div> 
15

還有另一種方式,沒有一次性技巧,這也需要少一點工作,很適合小幫手。這個助手的

@helper MyHelper(string title, Func<object, object> markup) { 
    <div class="module"> 
     <h3>Title</h3> 
     <div> 
      <p>@markup.DynamicInvoke(this.ViewContext)</p> 
     </div> 
    </div> 
} 

用法是這樣的:

@MyHelper("This is my Title", 
    @<p>Here is my custom markup</p> 
) 

或者多行:

@MyHelper("This is my Title", 
    @<text> 
     <p>More than one line</p> 
     <p>Of markup</p> 
    </text> 
) 

Telerik的MVC控件中使用這一招,例如,讓您在添加JavaScript代碼文件加載。

這裏也是一個不錯的example。還有一些信息here

+0

我喜歡這個例子。看起來更容易實施。你能幫我解決一個問題嗎? this.ViewContext不會編譯,因爲MyHelper方法是靜態的(至少我已經在我的幫助器中設置了它)。 – 2013-01-05 08:11:11

+1

令人驚訝的是,如果您將它傳遞給null,它也可以工作,但也許可能會出現一些會崩潰的複雜場景。無論如何,通過使用屬性ViewContext,您應該能夠通過Htmlhelper對象訪問ViewContext(如果您的靜態方法是html擴展方法,您應該有權訪問它)。如果不是這種情況,可以手動將ViewContext傳遞給方法。 – slawek 2013-01-06 23:29:39

+0

謝謝你的迴應。傳遞null工作。我認爲我的代碼無法訪問ViewContext的原因是因爲我正在構建一個MVC站點而不是應用程序。它正在工作。我相信你的回答是最好的,因爲它很簡單,有效。 – 2013-01-07 06:01:11