Я пытаюсь написать в Razor помощника, который выглядит следующим образом:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
К сожалению, синтаксический анализатор считает, что <T
это начало HTML-элемента, и я получаю синтаксическую ошибку. Можно ли с помощью Razor создать помощника, который является универсальным методом? Если да, то каков синтаксис?
asp.net-mvc
generics
asp.net-mvc-3
razor
mkedobbs
источник
источник
static
, если это не запрещено деталями реализации; Причина в том, что можно использовать общие помощники по расширению :@helper Foo<T>(this T o) where T : IBar { }
Ответы:
Нет, в настоящее время это невозможно. Вместо этого вы можете написать обычный помощник 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 TModel : class { ... }
что позволит вам вызывать его вот так (конечно, при условии, что ваше представление строго типизировано, но это безопасное предположение, потому что все представления в любом случае должны быть строго типизированными :-)):
источник
Это является возможным достижение внутри хелперов файла с
@functions
синтаксисом , но если вы хотите читаемость бритва стиль вы имеете в виду вам необходимо будет также вызывать регулярные помощника , чтобы сделать HTML подгонки и отделки.Обратите внимание, что функции в файле Helper статичны, поэтому вам все равно потребуется передать экземпляр HtmlHelper со страницы, если вы собираетесь использовать его методы.
например, Views \ MyView.cshtml:
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> } ...
источник
System.Web.WebPages.Html.HtmlHelper
вместоSystem.Web.Mvc.HtmlHelper
. Велика вероятность, что этаWebPages
версия вам не подойдет, поскольку большинство методов расширения написаны противSystem.Web.Mvc.HtmlHelper
. Кроме того, здесь нетUrl
свойства, иUrlHelper
требуется,RequestContext
что он недоступен вWebPages
версии. В общем, вам, вероятно, придется пройти вMvc
HtmlHelper
.{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_Code
.DoSomething
должен быть статическим, чтобы вы могли вызывать его@MyHelper.DoSomething(..)
в своем представлении. Если вы сделаете его нестатичным, вамMyHelper
сначала нужно будет создать экземпляр .Во всех случаях
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 {}
блок, но так и не смог заставить ее работать по этому пути.источник
TModel
вы наверняка знаете это заранее.если ваша основная проблема состоит в том, чтобы получить значение атрибута имени для привязки с использованием лямбда-выражения, похоже
@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"/> }
тогда здесь вы можете использовать это
источник
@Htm.IdFor
но вам нужен дополнительный процесс для преобразования его в string (.ToHtmlString()
), где помощнику требуется строка