ASP.Net MVC3 - 将Razor标记作为参数传递

25

我有一个名为 EditableArea 的帮助程序,它通过JS向用户提供可在运行时编辑的 div 。 EditableArea 帮助程序检查是否存在具有指定ID的可编辑区域(与 MVC 的 Area 无关),如果存在,则呈现该区域的HTML,否则它会显示帮助程序参数中指定的默认标记:

@Html.EditableArea(someId, "<p>Click to edit contents</p>")

一切都正常工作,但我想将默认的标记语言更改为Razor语法,而不是字符串形式,类似于:

@using (Html.EditableArea(someId))
{
    <p>Click to edit contents</p>
}

或者类似于MVC3中的@section的方式。

我该如何实现这一点?

我可以创建一个IDisposable,在其中的Dispose()方法中关闭TagBuilder等,但使用这种方法,标记仍将被呈现(我可以在Dispose()中清除呈现的内容,但代码块仍将不必要地运行,我想避免这种情况)。

是否有其他方法将Razor块传递给助手,这些块可能或可能不会实际呈现?

4个回答

29

这是一个我用来渲染jQuery模板标记的例子,方法是通过传入模板ID和模板本身的Razor格式语法:

public static MvcHtmlString jQueryTmpl(this HtmlHelper htmlHelper, 
    string templateId, Func<object, HelperResult> template) 
{
    return MvcHtmlString.Create("<script id=\"" + templateId + 
        "\" type=\"x-jquery-tmpl\">" + template.Invoke(null) + "</script>");
}

并且这将会被调用

@Html.jQueryTmpl("templateId", @<text>any type of valid razor syntax here</text>)

只需将Func<object, HelperResult>用作参数,然后使用template.Invoke(null)(如果需要,则带有参数)对其进行渲染。显然,您可以跳过调用.Invoke()以避免呈现“默认”标记。


它无法正常工作。函数调用内的<text>...</text>语法未被识别(无效的表达式项“<”)。 - Boris B.
1
太好了,现在它可以工作了。<text>标签根本不需要(@就足够了),除非Razor标记实际上是没有任何标签的纯文本,否则只需使用@<tag>即可。 - Boris B.
1
关于<text>标签的部分是正确的。我倾向于使用它们,以防将来更改模板中的内容 - 未雨绸缪。 - Marek Karbarz
为什么将 null 传递给模板函数?参数的作用是什么? - Triynko
"IHtmlHelper<dynamic>"没有定义'jQueryTmpl',也没有找到可访问的扩展方法'jQueryTmpl',接受类型为'IHtmlHelper<dynamic>'的第一个参数(是否缺少使用指令或程序集引用?) 没有MVC Core? - bh_earth0

3

为了扩展接受的答案,因为我花了很长时间来解决类似的问题,并且这是弹出的问题。我真正需要的是@helper,它可以接受razor文本,因为模板应该包含相当多的代码。我尝试使用网上找到的几个版本的类型@helper item(Func<object, HelperResult> input),但没有成功。因此,我采用了以下方法:

namespace project.MvcHtmlHelpers
{
    public static class HelperExtensions
    {
        public static MvcHtmlString RazorToMvcString(this HtmlHelper htmlHelper, Func<object, HelperResult> template)
        {
            return MvcHtmlString.Create(template.Invoke(null).ToString());
        }
    }
}

并且。
@project.MvcHtmlHelpers    
@helper item(other input, MvcHtmlString content)
    {
        <div class="item">
            ...other stuff... 
            <div class="content">
                @content
            </div>
        </div>
    }

并通过此方式使用

@item(other input, @Html.RazorToMvcString(@<text>this is a test</text>))

现在我可以使用助手模板来处理Razor输入,但我也可以插入部分视图,这在某些情况下非常方便。虽然我不是专家,但似乎这是一种灵活的方法。


3
如果您想知道如何在asp.net core 3.1中完成此操作,请参考以下步骤。
@{
    void TemplateFunc(Func<object, IHtmlContent> template)
    {
        <div>@template(null)</div>
    }
}

然后在标记中,您可以将其用作:
<div>
@{TemplateFunc(@<div>123</div>);}
</div>

-1
进一步来说,可以直接将标记传递给帮助程序,而不需要扩展方法。
@helper HelperWithChild(Func<object, HelperResult> renderChild)
{
    <div class="wrapper">
        @renderChild(this)
    </div>
}

@HelperWithChild(@<h1>Hello</h1>)

对于多行标记,也需要使用<text>

@HelperWithChild(@<text>
    @AnotherHelper()

    <h1>
        With more markup
    </h1>
</text>)

@helper AnotherHelper()
{
    <p>
        Another helper
    </p>
}

虽然我不确定这会如何与Model配合使用 - 我的帮助程序只使用它们的参数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接