90 votes

Est-il possible de créer une méthode @helper générique avec Razor ?

J'essaie d'écrire une aide dans Razor qui ressemble à ce qui suit :

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

Malheureusement, l'analyseur pense que <T est le début d'un élément HTML et je me retrouve avec une erreur de syntaxe. Est-il possible de créer un helper avec Razor qui soit une méthode générique ? Si oui, quelle est la syntaxe ?

0 votes

Toujours pas corrigé dans la version actuelle de MVC 4 :(

1 votes

Comment se fait-il que ce problème ne soit toujours pas résolu dans VS2012 ?

7 votes

Bon sang, j'ai hâte que cela soit ajouté ; j'espère que c'est quelque part autour de " le mettre en œuvre hier " sur la liste des priorités. Partiellement hors sujet, mais à côté de cela, j'aimerais que les classes générées soient static à moins que des détails d'implémentation ne l'interdisent ; la raison étant que l'on pourrait utiliser aides génériques à l'extension : @helper Foo<T>(this T o) where T : IBar { }

127voto

chrismilleruk Points 1321

Ce site es possible de réaliser à l'intérieur d'un fichier d'aide avec l'option @functions syntaxe, mais si vous voulez obtenir la lisibilité de style rasoir à laquelle vous faites référence, vous devrez également faire appel à un assistant régulier pour effectuer l'ajustement et la finition du HTML.

Notez que les fonctions d'un fichier Helper sont statiques. Vous devrez donc toujours transmettre l'instance HtmlHelper de la page si vous avez l'intention d'utiliser ses méthodes.

par exemple Vues \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>
}
...

0 votes

Il n'est pas nécessaire de rendre la méthode statique et, par conséquent, il n'est pas non plus nécessaire de passer votre Html/Url/Model, etc.

0 votes

Hmmm pourquoi ça ne marche pas pour moi ? J'obtiens un "Cannot access non-static method 'TheThingToDo' in static context"

0 votes

Cela a fonctionné pour moi une fois que j'ai supprimé le mot clé static de la signature de la méthode "DoSomething".

52voto

Darin Dimitrov Points 528142

Non, ce n'est pas possible actuellement. Vous pouvez écrire une aide HTML normale à la place.

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

et ensuite :

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

ou si vous ciblez le modèle comme premier argument générique :

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

qui vous permettra de l'invoquer comme ceci (en supposant bien sûr que votre vue est fortement typée, mais c'est une supposition sûre car toutes les vues devraient être fortement typées de toute façon :-)) :

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

10 votes

Espérons qu'il s'agit d'un élément qu'ils ajouteront à une future version des assistants Razor. La lisibilité d'une aide traditionnelle est beaucoup plus faible que la syntaxe @helper.

2 votes

Oui, d'accord. Revenir à l'ancienne méthode, non seulement ça craint, mais ça divise les aides de façon arbitraire !

3voto

bradlis7 Points 553

Dans tous les cas, le TModel sera le même (le modèle déclaré pour la vue), et dans mon cas, l'élément TValue allait être le même, j'ai donc pu déclarer le type d'argument 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>
}

Si les champs de votre modèle sont tous string alors vous pouvez remplacer MyClass con string .

Il n'est peut-être pas mauvais de définir deux ou trois aides avec le programme TValue définis, mais si vous en avez d'autres qui généreraient un code moche, je n'ai pas vraiment trouvé de bonne solution. J'ai essayé d'envelopper le @helper à partir d'une fonction que j'ai placée dans le @functions {} mais je n'ai jamais réussi à le faire fonctionner de cette façon.

0 votes

C'est assez évident quand on y pense, si c'est TModel vous le savez probablement d'avance.

0voto

ktutnik Points 1711

Si votre principal problème est d'obtenir nom pour la liaison à l'aide d'une expression lambda semble être la solution la plus efficace. @Html.TextBoxFor(x => x.MyPoperty) Si votre composant comporte des balises html très complexes et qu'il doit être mis en œuvre sur l'assistant Razor, pourquoi ne pas créer une méthode d'extension de l'assistant Razor ? HtmlHelper<TModel> pour résoudre le nom de la liaison :

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

votre assistant de rasage devrait être comme d'habitude :

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

alors ici vous pouvez l'utiliser

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

0 votes

N'est-ce pas à cela que sert @Html.IdFor(...) ?

0 votes

Oui, vous pouvez le faire avec @Htm.IdFor mais il faut un processus supplémentaire pour le convertir en chaîne de caractères ( .ToHtmlString() ) où la chaîne d'aide requise

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X