私は次のようなヘルパーでヘルパーを書こうとしています:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
残念ながら、パーサーはそれ<T
がHTML要素の始まりであると考え、構文エラーが発生します。ジェネリックメソッドであるRazorでヘルパーを作成することは可能ですか?もしそうなら、構文は何ですか?
私は次のようなヘルパーでヘルパーを書こうとしています:
@helper DoSomething<T, U>(Expression<Func<T, U>> expr) where T : class
残念ながら、パーサーはそれ<T
がHTML要素の始まりであると考え、構文エラーが発生します。ジェネリックメソッドであるRazorでヘルパーを作成することは可能ですか?もしそうなら、構文は何ですか?
static
、実装の詳細で禁止されていない限り、生成されたクラスがであることを確認したいと思います。であることの理由は、1を使用することができている一般的な拡張ヘルパーを:@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 T : class
{
...
}
これにより、次のように呼び出すことができます(もちろん、ビューが強く型付けされていると仮定しますが、すべてのビューはとにかく強く型付けされる必要があるため、これは安全な仮定です:-)):
@Html.DoSomething(x => x.SomeProperty)
これは、@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>
}
...
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
同じになるため、式の引数の型を宣言することができました。
@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
。
2つまたは3つのヘルパーを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"/>
}
次に、あなたはそれを使うことができます
@TheHelper.MyComponent(Html.GetNameForBinding(x => x.MyProperty))
@Htm.IdFor
とする文字列(.ToHtmlString()
)に変換するための追加のプロセスが必要です