Razor ile jenerik bir @helper yöntemi oluşturmak mümkün müdür?


90

Razor'da aşağıdakine benzeyen bir yardımcı yazmaya çalışıyorum:

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

Ne yazık ki, ayrıştırıcı bunun <Tbir HTML öğesinin başlangıcı olduğunu düşünüyor ve ben bir sözdizimi hatasıyla karşılaşıyorum. Jenerik bir yöntem olan Razor ile yardımcı oluşturmak mümkün müdür? Eğer öyleyse, sözdizimi nedir?


Halen mevcut MVC 4 sürümünde düzeltilmedi. :(
Alex Dresko

1
Bu hala VS2012'de nasıl düzeltilmedi?
Alex Dresko

7
Tanrım, bunun eklenmesini bekleyemem; Umarım bu, öncelik listesinde " dün uygula " etrafında bir yerdedir . Kısmen konu dışı, ancak bunun yanında static, uygulama ayrıntıları bunu yasaklamadıkça, oluşturulan sınıfların olduğunu görmek isterim ; nedeni, genel uzantı yardımcılarının kullanılabilmesidir :@helper Foo<T>(this T o) where T : IBar { }
Dan Lugg

Yanıtlar:


52

Hayır, bu şu anda mümkün değil. Bunun yerine normal bir HTML yardımcısı yazabilirsiniz.

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

ve sonra:

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

veya modeli ilk genel bağımsız değişken olarak hedefliyorsanız:

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

Bu, onu bu şekilde çağırmanıza izin verecektir (elbette, görünümünüzün güçlü bir şekilde yazılmış olduğunu varsayarsak, ancak bu güvenli bir varsayım çünkü tüm görünümler yine de güçlü bir şekilde yazılmalıdır :-)):

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

10
Umarım bu, Razor yardımcılarının gelecekteki bir sürümüne ekledikleri bir şeydir. Geleneksel bir yardımcının okunabilirliği @helper sözdiziminden çok daha düşüktür.
mkedobbs

2
Evet kabul etti. Eski yönteme dönmek sadece berbat olmakla kalmaz, aynı zamanda yardımcılarınızı keyfi olarak böler!
George R.

127

Bu ,@functions sözdizimi ile bir yardımcı dosyanın içinde elde etmek mümkündür, ancak bahsettiğiniz ustura tarzı okunabilirliği istiyorsanız, HTML sığdırması ve bitirmesi için normal bir yardımcı çağırmanız da gerekecektir.

Bir Helper dosyasındaki işlevlerin statik olduğunu ve bu nedenle, yöntemlerini kullanmayı planlıyorsanız sayfadan HtmlHelper örneğini geçirmeniz gerekeceğini unutmayın.

örneğin Görünümler \ 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>
}
...

Yöntemi statik hale getirmek zorunda YOKTUR ve bu nedenle Html / Url / Model vb. Bilgilerinizi
Sheepy

Hmmm neden bu benim için çalışmıyor? "Statik bağlamda statik olmayan '
TheThingToDo

12
@Sheepy, bu sadece yarısı doğru. Haklısın, onları statik olmayan yapabilirsin, ama sadece System.Web.WebPages.Html.HtmlHelperyerine alırsın System.Web.Mvc.HtmlHelper. WebPagesÇoğu uzatma yöntemi aleyhine yazıldığından , sürümün size uygun olmaması için mükemmel bir şans var System.Web.Mvc.HtmlHelper. Dahası, yokUrl özellik ve sürümde bulunmayan UrlHelperbir özelliği gerektirir . Sonuçta muhtemelen geçmek zorunda kalacaksınız . RequestContextWebPagesMvc HtmlHelper
Kirk Woll

1
yardımcı, App_Code Klasörünün bir parçası olmalı ??
Vishal Sharma

1
Evet, bu dosya {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` içine yerleştirilmelidir App_Code. sizin görüşünüzde DoSomethingarayabilmeniz için statik olmalıdır @MyHelper.DoSomething(..). Statik olmayan yaparsanız, MyHelperönce bir örnek oluşturmanız gerekir .
Grilse

3

Her durumda TModelaynı olacaktır (görünüm için bildirilen model) ve benim durumumda TValueaynı olacaktı, bu nedenle İfade argüman tipini bildirebildim:

@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>
}

Modeliniz alanlar hepsi ise string, o zaman yerini alabilir MyClassile string.

İki ya da üç yardımcıyı şu şekilde tanımlamak kötü olmayabilir. TValueTanımlanan , ancak çirkin bir kod üretecek daha fazlasına sahipseniz, gerçekten iyi bir çözüm bulamadım. Bloğun @helperiçine koyduğum bir fonksiyondan sarmayı denedim @functions {}, ama asla o yolda çalışmadım.


Düşündüğünüzde biraz açık - eğer TModelvarsa muhtemelen önceden biliyorsunuzdur.
ta.speot.is

0

senin asıl sorun olsun eğer adı lambda ifade kullanarak bağlanma için öznitelik değerini gibi görünüyor @Html.TextBoxFor(x => x.MyPoperty), ve bileşen çok karmaşık html etiketleri sahip ve jilet yardımcı üzerine uygulanacak olursa, o zaman neden sadece bir uzantısı yöntemini oluşturmaz HtmlHelper<TModel>çözmek için bağlayıcı adı:

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);
        }
    }
}

jilet yardımcınız her zamanki gibi olmalı:

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

o zaman burada kullanabilirsin

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

@ Html.IdFor (...) bunun için değil mi?
Alex Dresko

Evet, bunu yapabilirsiniz, @Htm.IdForancak .ToHtmlString()yardımcının dize gerektirdiği dizgeye ( ) dönüştürmek için fazladan işleme ihtiyacınız var
ktutnik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.