Можно ли создать общий метод @helper с помощью Razor?
Я пытаюсь написать помощника в Razor, который выглядит следующим образом:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
К сожалению, парсер считает, что <T
- это начало элемента HTML, и я получаю синтаксическую ошибку. Возможно ли создать помощника с Razor, который является общим методом? Если да, то какой синтаксис?
Ответы
Ответ 1
Нет, это невозможно. Вместо этого вы могли бы написать обычный 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
Этот можно реализовать внутри вспомогательного файла с синтаксисом @functions
, но если вы хотите, чтобы читаемость в стиле бритвы вы ссылались на вас, вам также нужно будет вызвать обычного помощника, чтобы выполнить HTML подходит и закончен.
Обратите внимание, что функции в файле Helper являются статическими, поэтому вам все равно нужно передать экземпляр HtmlHelper со страницы, если вы собираетесь использовать его методы.
например.
Просмотров \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>
}
...
Ответ 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
, вы можете заменить MyClass
на string
.
Возможно, было бы неплохо определить два или три помощника с указанным TValue
, но если у вас есть еще что-то, что создаст какой-то уродливый код, я действительно не нашел хорошего решения. Я попробовал обернуть @helper
из функции, помещенной внутри блока @functions {}
, но у меня никогда не было этого, чтобы работать по этому пути.
Ответ 4
если ваша основная проблема заключается в том, чтобы получить значение атрибута name для привязки с использованием лямбда-выражения, похоже на @Html.TextBoxFor(x => x.MyPoperty)
, и если ваш компонент имеет очень сложные html-теги и должен быть реализован на помощнике бритвы, тогда почему бы не просто создать метод расширения 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))