IEnumerable <TModel>
TModel がモデル オブジェクト タイプであるビューから Html テーブルを簡単に作成できる顧客 HtmlHelper を作成しようとしています。ビューからの呼び出し構文を次のスタイルにしたいと思います。
@Html.TableFor(model => model.AddedUserID, model => model.ClientID......., model model => AnothreFildIWantDisplayed));
最初に1つの式を渡してこれを機能させようとすることから始めています。
@Html.TableFor(model => model.AddedUserID)
それが機能したら、params を使用して複数の式を取得するカンマ区切りのリストを取得します。
私のビューコードは次のようになります
@using MyNameSpaceToMyHelper
@model IEnumerable<User>
@{
ViewBag.Title = "Index";
}
<p>
</p>
@Html.TableFor(model => model.AddedUserID));
HtmlHelper を書く私の試みは次のとおりです。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.UI;
namespace MyNameSpaceToMyHelper
{
public static class GridExtensions
{
public static MvcHtmlString TableFor<TModel, TValue>(this HtmlHelper<IEnumerable<TModel>> html, Expression<Func<TModel, TValue>> expression)
{
var writer = new HtmlTextWriter(new StringWriter());
writer.RenderBeginTag(HtmlTextWriterTag.Table);
writer.RenderBeginTag(HtmlTextWriterTag.Thead);
writer.RenderBeginTag(HtmlTextWriterTag.Th);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
//Colum Headers
writer.Write(html.DisplayNameFor(expression));
writer.RenderEndTag();
writer.RenderEndTag();
writer.RenderEndTag();//Close THead
//Column Data
//html.DisplayFor((Expression<Func<TModel, TValue>>)expression);
foreach (ViewDataDictionary<TModel> vdm in html.ViewData.Values)
{
writer.RenderBeginTag(HtmlTextWriterTag.Tr);
writer.RenderBeginTag(HtmlTextWriterTag.Td);
//DOESN'T COMPILE
html.DisplayFor(expression);
writer.RenderEndTag();
writer.RenderEndTag();
}
writer.RenderEndTag(); //Close Header
return new MvcHtmlString(writer.InnerWriter.ToString());
}
}
}
次の理由により、これはコンパイルされません。
html.DisplayFor(式);
私の理解によると、これは、メソッドに渡された HtmlHelper が for であるのHtmlHelper<IEnumerable<TModel>>
に対し、それを使用する場合DisplayFor
はHtmlHelper<TModel>
.
このエラーのため、テーブル ヘッダーとデータを 2 つの個別のメソッド呼び出しに分割することでこれを機能させることができるように思われます。私のビューからは、ヘッダー メソッドを呼び出してから、実際のビュー内にそれぞれのメソッドを呼び出す for ループを含めることができます。列とか。このようなもの
@using MyNameSpaceToMyHelper
@model IEnumerable<User>
@{
ViewBag.Title = "Index";
}
<p>
</p>
@Html.TableHeadersFor(model => model.AddedUserID));
@foreach (var item in Model) {
@Html.TableRowsFor(model => model.AddedUserID));
}
これは、互換性のない HtmlHelper タイプの問題がなくなるため、を取り、を取り、 を呼び出すことができるため、TableHeadersFor
機能するはずです。DisplayNameExtensions.DisplayNameFor
HtmlHelper<IEnumerable<TModel>>
TableRowsFor
HtmlHelper<TModel>
DisplayExtensions.DisplayFor
HtmlHelper<TModel>
ただし、呼び出し構文をできるだけ単純にしたいので、可能な限りこれを行うことは理想的ではありません。私の質問の基本的な前提は、ビューに for ループを記述したり、列を選択するための式を複製したりせずに、単純な呼び出し構文を維持しようとすることです。ここでの全体的な目的は、再利用可能で他の人ができるだけ使いやすいものを設計することです
ILSpy で、DisplayNameExtensions.DisplayNameFor
これがどのように機能するかを調べました。これは、拡張メソッドを内部で呼び出している拡張メソッドのHtmlHelper<IEnumerable<TModel>>
ように見えますが、ILSpy が生成しているコードは再コンパイルさえしないため、.Net がどのように理解されているかわかりません。これを行うことができます。HtmlHelper<IEnuermable<TModel>>
HtmlHelper<TModel>
これは 1 つの拡張メソッドで可能ですか、それとも呼び出し構文を妥協して分割する必要がありますか?
UPDATE 1 私はかなり多くの作業で次の作業を行うことができました:
@Html.BeginTableFor(model => model.AddedUserID
, model => model.Active
, new { @class = "grid" })
@foreach (var item in Model) {
@Html.DisplayRowFor(model => item.AddedUserID
, model => item.Active)
}
@Html.EndTableFor()
これは私が望むほど簡潔ではなく、特に BeginTableFor と DisplayRowFor の各式が異なる型を返す可能性があるため、多くの作業が必要です。つまり、基本的に任意の数の式に対してメソッドのオーバーロードを実装する必要がありました (私は 100 個まで実行しました)。そのため、最大 100 列まで機能します!)。これは基本的に、アクション T1、T2、..、T16 などの異なる数のパラメーターに対して異なるバージョンを記述しなければならなかった Action デリゲートと Func デリゲートを使用して .Net で発生した問題と同じです。明らかに非常に面倒ですが、多くのメソッドのオーバーロードを避けるよりも、適切な呼び出し構文が必要です。