web-dev-qa-db-ja.com

Razorで一般的な@helperメソッドを作成することはできますか?

Razorで次のようなヘルパーを作成しようとしています。

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

残念ながら、パーサーは<TはHTML要素の始まりであり、構文エラーになります。一般的な方法であるRazorでヘルパーを作成することはできますか?もしそうなら、構文は何ですか?

85
mkedobbs

いいえ、これは不可能です。代わりに、通常の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)
50
Darin Dimitrov

このisは、@functions構文ですが、参照しているカミソリスタイルの読みやすさを望む場合は、通常のヘルパーを呼び出してHTMLのフィットとフィニッシュを行う必要もあります。

ヘルパーファイルの関数は静的であるため、そのメソッドを使用する場合は、ページからHtmlHelperインスタンスを渡す必要があります。

例えばViews\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>
}
...
122
chrismilleruk

すべての場合で、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の場合、MyClassstringに置き換えることができます。

TValueを定義して2つまたは3つのヘルパーを定義するのは悪くないかもしれませんが、それ以上いコードを生成するものがある場合、私は本当に良い解決策を見つけませんでした。 @helperブロック内に配置した関数から@functions {}をラップしようとしましたが、そのパスで機​​能することはありませんでした。

3
bradlis7

主な問題が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))
0
ktutnik