Saya mencoba menulis pembantu di Razor yang terlihat seperti berikut:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
Sayangnya, pengurai berpikir itu <T
adalah awal dari elemen HTML dan saya berakhir dengan kesalahan sintaksis. Apakah mungkin membuat helper dengan Razor yang merupakan metode umum? Jika ya, apa sintaksnya?
asp.net-mvc
generics
asp.net-mvc-3
razor
mkedobbs
sumber
sumber
static
, kecuali jika detail implementasi melarangnya; Alasannya, adalah seseorang dapat menggunakan pembantu ekstensi generik :@helper Foo<T>(this T o) where T : IBar { }
Jawaban:
Tidak, saat ini tidak memungkinkan. Sebagai gantinya, Anda bisa menulis pembantu HTML biasa.
public static MvcHtmlString DoSomething<T, U>( this HtmlHelper htmlHelper, Expression<Func<T, U>> expr ) where T : class { ... }
lalu:
@(Html.DoSomething<SomeModel, string>(x => x.SomeProperty))
atau jika Anda menargetkan model sebagai argumen umum pertama:
public static MvcHtmlString DoSomething<TModel, TProperty>( this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expr ) where TModel : class { ... }
yang memungkinkan Anda untuk memanggilnya seperti ini (tentu saja dengan asumsi bahwa pandangan Anda diketik dengan kuat, tetapi itu adalah asumsi yang aman karena semua tampilan harus diketik dengan kuat :-)):
sumber
Hal ini dimungkinkan untuk dicapai di dalam file helper dengan
@functions
sintaks tetapi jika Anda menginginkan keterbacaan gaya pisau cukur yang Anda maksud, Anda juga perlu memanggil helper biasa untuk melakukan fit dan menyelesaikan HTML.Perhatikan bahwa fungsi dalam file Helper bersifat statis sehingga Anda masih perlu meneruskan instance HtmlHelper dari halaman jika Anda bermaksud menggunakan metodenya.
mis. 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> } ...
sumber
System.Web.WebPages.Html.HtmlHelper
daripadaSystem.Web.Mvc.HtmlHelper
. Ada kemungkinan besar bahwaWebPages
versi tersebut tidak akan cocok untuk Anda, karena sebagian besar metode ekstensi tidak sesuaiSystem.Web.Mvc.HtmlHelper
. Selain itu, tidak adaUrl
properti, danUrlHelper
membutuhkanRequestContext
yang tidak tersedia dalamWebPages
versi. Semua di dalam semua Anda mungkin harus lulus diMvc
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` keApp_Code
.DoSomething
harus statis, sehingga Anda dapat memanggil@MyHelper.DoSomething(..)
dalam tampilan Anda. Jika Anda membuatnya non-statis, Anda harus membuat instanceMyHelper
terlebih dahulu.Dalam semua kasus,
TModel
akan sama (model dideklarasikan untuk tampilan), dan dalam kasus saya,TValue
tadinya akan sama, jadi saya bisa mendeklarasikan tipe argumen Ekspresi:@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> }
Jika bidang model Anda semuanya
string
, maka Anda dapat menggantinyaMyClass
denganstring
.Mungkin tidak buruk untuk mendefinisikan dua atau tiga pembantu dengan yang
TValue
ditentukan, tetapi jika Anda memiliki lebih banyak yang akan menghasilkan beberapa kode jelek, saya tidak benar-benar menemukan solusi yang baik. Saya mencoba membungkus@helper
dari fungsi yang saya masukkan ke dalam@functions {}
blok, tetapi saya tidak pernah berhasil melakukannya di jalur itu.sumber
TModel
Anda mungkin mengetahuinya sebelumnya.Jika masalah utama Anda adalah mendapatkan nilai atribut nama untuk mengikat menggunakan ekspresi lambda sepertinya
@Html.TextBoxFor(x => x.MyPoperty)
, dan jika komponen Anda memiliki tag html yang sangat kompleks dan harus diterapkan pada pisau cukur, mengapa tidak membuat metode ekstensiHtmlHelper<TModel>
untuk menyelesaikan nama yang mengikat: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); } } }
pisau cukur Anda harus seperti biasa:
@helper MyComponent(string name) { <input name="@name" type="text"/> }
lalu di sini Anda bisa menggunakannya
sumber
@Htm.IdFor
tetapi memerlukan proses ekstra untuk mengubahnya menjadi string (.ToHtmlString()
) di mana helper memerlukan string