是否可以使用Razor创建通用的@helper方法?

时间:2011-01-21 15:52:16

标签: asp.net-mvc generics asp.net-mvc-3 razor

我正在尝试在Razor中编写一个如下所示的帮助器:

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

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

4 个答案:

答案 0 :(得分:122)

这个 可以在@functions语法的辅助文件中实现,但是如果你想要你所指的剃刀风格的可读性,你还需要调用一个常规帮助器来做HTML适合并完成。

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

e.g。 视图\ 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>
}
...

答案 1 :(得分:48)

不,这是不可能的。您可以改为编写普通的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)

答案 2 :(得分:2)

在所有情况下,TModel都是相同的(为视图声明的模型),在我的情况下,TValue将是相同的,所以我能够声明表达式参数类型:

@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,则可以将MyClass替换为string

定义两个或三个助手TValue定义可能并不坏,但如果你还有更多会产生一些丑陋的代码,我真的找不到一个好的解决方案。我尝试从我放在@helper块中的函数中包装@functions {},但我从来没有让它在那条路上工作。

答案 3 :(得分:0)

如果您的主要问题是使用l​​ambda表达式获取绑定的 name 属性值,则看起来像@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))