【问题标题】:MVC 3 Razor, Helpers with custom markup/sectionMVC 3 Razor,具有自定义标记/部分的助手
【发布时间】:2012-02-23 15:49:07
【问题描述】:

我什至不确定这是否可能,但我想我会检查一下是否有任何方法可以使这更容易。

首先,我的网站中有一些重复的标记,如下所示:

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

然后,当它渲染时,它会在 &lt;h3&gt;&lt;/h3&gt; 和 div 中的自定义标记之间注入通过参数传入的标题。自定义标记可以是任何东西,从测试到表单控件,再到局部视图。这有可能吗?

【问题讨论】:

    标签: asp.net-mvc-3 razor html-helper


    【解决方案1】:

    嗯,这是一种接近它的“标准”方式,使用 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>
    }
    

    【讨论】:

    • 这正是我想要的。
    • stackoverflow.com/questions/7196276/…有一个更简单的例子
    • 考虑到解决方案完全相同,我很难看出是什么让它变得更简单......此示例中唯一的附加代码是为了满足问题中的要求 - 以及基本检查以避免 Dispose 被调用两次的副作用。
    【解决方案2】:

    如果您使用的是 Razor 和 MVC 3,那么编写一个快速帮助方法非常容易,该方法将进入 app_code 文件夹(我将其命名为 MyHtmlHelpers)

    我会尝试一些不同的、更简单的方法,例如:

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

    您从 .cshtml 文件中使用它的方式如下:

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

    如果我理解正确的话,它应该可以工作。

    【讨论】:

    • 我不希望标记成为字符串参数,因为我希望在我的视图中将标记作为常规 html。我想做的是用 MVC 3 中的助手来模仿在 MVC 2 中你可以拥有&lt;% using(Html.Beginform()) { %&gt; html markup &lt;% } %&gt;
    【解决方案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>
    

    【讨论】:

      【解决方案4】:

      还有另外一种方式,不用一次性的把戏,也少了一点工作量,非常适合小帮手。

      @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

      【讨论】:

      • 我喜欢这个例子。似乎更容易实现。你能帮我解决一个问题吗? this.ViewContext 无法编译,因为 MyHelper 方法是静态的(至少我在助手中设置了它)。
      • 令人惊讶的是,如果您将其传递为 null,它往往也能正常工作,但可能会有一些复杂的场景会崩溃。无论如何,您应该能够使用属性 ViewContext 通过 Htmlhelper 对象访问 ViewContext(如果您的静态方法是 html 扩展方法,您应该可以访问它)。如果不是这种情况,您可以手动将 ViewContext 传递给该方法。
      • 感谢您的回复。传递 null 有效。我认为我的代码无法访问 ViewContext 的原因是因为我正在构建一个 MVC 站点而不是应用程序。它现在正在工作。我认为您的答案是最好的,因为它简单且有效。
      猜你喜欢
      • 1970-01-01
      • 2019-11-07
      • 2014-09-02
      • 2012-09-13
      • 2011-06-10
      • 2021-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多