2012-01-31 85 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