是否可以使用Razor创建泛型@helper方法?


88

我试图在Razor中编写一个类似于以下内容的助手:

@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class

不幸的是,解析器认为这<T是HTML元素的开始,最后出现语法错误。是否可以使用Razor创建通用方法的助手?如果是这样,语法是什么?


在当前的MVC 4版本中仍未修复。:(
亚历克斯·德雷斯科

1
在VS2012中如何仍不能解决此问题?
亚历克斯·德雷斯科

7
天哪,我等不及要添加了。我希望这是优先列表上“ 昨天实施 ”的地方。部分偏离主题,但与此同时,我希望看到生成的类是static,除非实现细节禁止使用它;否则,请参见。原因是,有人可以使用通用扩展助手@helper Foo<T>(this T o) where T : IBar { }
Dan Lugg

Answers:


52

不,这是不可能的。您可以改为编写普通的HTML帮助器。

public static MvcHtmlString DoSomething<T, U>(
    this HtmlHelper htmlHelper, 
    Expression<Func<T, U>> expr
) where T : class
{
    ...
}

然后:

@(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))

或者如果您将模型作为第一个通用参数作为目标:

public static MvcHtmlString DoSomething<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper, 
    Expression<Func<TModel, TProperty>> expr
) where T : class
{
    ...
}

这将允许您像这样调用它(当然假设您的视图是强类型的,但这是一个安全的假设,因为所有视图无论如何都应该是强类型的:-)):

@Html.DoSomething(x => x.SomeProperty)

10
希望这是他们在Razor帮助程序的未来版本中添加的内容。传统帮助程序的可读性远低于@helper语法。
mkedobbs 2011年

2
是的,同意。恢复到较旧的方法不仅很烂,而且会任意分割您的助手!
乔治·R

126

有可能实现与一个帮助文件中@functions的语法,但如果你想你指的是你的剃须刀式的可读性也需要调用一个常规帮手做HTML适应和完成。

请注意,Helper文件中的函数是静态的,因此,如果您打算使用HtmlHelper实例的方法,则仍需要从页面中传入它。

例如Views \ MyView.cshtml:

@MyHelper.DoSomething(Html, m=>m.Property1)
@MyHelper.DoSomething(Html, m=>m.Property2)
@MyHelper.DoSomething(Html, m=>m.Property3)

App_Code \ MyHelper.cshtml:

@using System.Web.Mvc;
@using System.Web.Mvc.Html;
@using System.Linq.Expressions;
@functions
{
    public static HelperResult DoSomething<TModel, TItem>(HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
    {
        return TheThingToDo(html.LabelFor(expr), html.EditorFor(expr), html.ValidationMessageFor(expr));
    }
}
@helper TheThingToDo(MvcHtmlString label, MvcHtmlString textbox, MvcHtmlString validationMessage)
{
    <p>
        @label
        <br />
        @textbox
        @validationMessage
    </p>
}
...

太棒了。谢谢。
肯·史密斯,

您不必将方法设为静态,因此也不需要传递Html / Url / Model等
Sheepy

12
@Sheepy,只有一半是正确的。您是正确的,可以使它们成为非静态的,但只能得到System.Web.WebPages.Html.HtmlHelper而不是System.Web.Mvc.HtmlHelper。该WebPages版本极有可能不适合您,因为大多数扩展方法都是针对编写的System.Web.Mvc.HtmlHelper。此外,没有Url财产,并UrlHelper要求RequestContext其处于不可用WebPages的版本。总而言之,您可能必须通过Mvc HtmlHelper
Kirk Woll '02

1
帮助程序必须是App_Code文件夹的一部分?
维沙尔·沙尔玛(Vishal Sharma)2013年

1
是的,此文件必须放在{MyMvcProject}\App_Code`. It doesn't work as advertised when you place it elsewhere. The error *Cannot access non-static method 'TheThingToDo' in static context* disappears when you move MyHelper.cshtml`中App_CodeDoSomething应该是静态的,以便您可以@MyHelper.DoSomething(..)在视图中调用。如果将其设置为非静态,则需要创建MyHelperfirst 的实例。
Grilse 2015年

3

在所有情况下,它们TModel都将是相同的(为视图声明的模型),而在我的情况下,将TValue是相同的,因此我能够声明Expression参数类型:

@helper FormRow(Expression<Func<MyViewModel, MyClass>> expression) {
  <div class="form-group">
    @(Html.LabelFor(expression, new { @class = "control-label col-sm-6 text-right" }))
    <div class="col-sm-6">
      @Html.EnumDropDownListFor(expression, new { @class = "form-control" })
    </div>
    @Html.ValidationMessageFor(expression)
  </div>
}

如果您的模型字段全部string,则可以替换MyClassstring

用已TValue定义的方法定义两个或三个助手可能并不坏,但是如果您还有其他可以生成一些难看代码的助手,那么我真的没有找到一个好的解决方案。我尝试@helper从放置在代码@functions {}块中的函数包装,但是我一直没找到它来解决这个问题。


当您考虑它时,这很明显-如果是,TModel您可能提前知道了。
ta.speot。是

0

如果您的主要问题是使用lambda表达式获取要绑定的名称属性值,例如@Html.TextBoxFor(x => x.MyPoperty),并且您的组件具有非常复杂的html标签,并且应在razor helper上实现,那么为什么不仅仅创建的扩展方法HtmlHelper<TModel>来解决绑定名称:

namespace System.Web.Mvc
{
    public static class MyHelpers
    {
        public static string GetNameForBinding<TModel, TProperty>
           (this HtmlHelper<TModel> model, 
            Expression<Func<TModel, TProperty>> property)
        {
            return ExpressionHelper.GetExpressionText(property);
        }
    }
}

您的剃须刀助手应该像往常一样:

@helper MyComponent(string name)
{
    <input name="@name" type="text"/>
}

然后在这里你可以使用它

@TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))

这不是@ Html.IdFor(...)的目的吗?
Alex Dresko 2013年

是的,您可以这样做,@Htm.IdFor但需要额外的过程才能将其转换.ToHtmlString()为助手需要字符串的字符串()
ktutnik 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.