如何使 WebGrid 列采用真正的 lambda 来实现类型安全?
How can I make WebGrid columns take a real lambda to be typesafe?
创建 WebGridColumn 时,需要为将要使用的 columnName 传入一个字符串。为什么它不允许像大多数其他 HTML 助手一样传递 lambda 表达式?我如何传递一个简单的 lambda 以获得智能提示、保留 type-safety 并防止因拼写错误导致的运行时错误?有了列名,WebGrid 难道不应该能够使用元数据显示属性来默认设置 header 和格式吗?
我们经常使用的东西:
@{ var grid = new WebGrid(model) }
@grid.GetHtml(
// table style formats here...
columns: grid.Columns(
grid.Column(columnName: "StudentName",
header: Html.DisplayNameFor(model => model.StudentName)),
grid.Column(columnName: "Birthdate",
header: Html.DisplayNameFor(model => model.Birthdate),
format: (item) => Html.DisplayFor(modelItem => (item as WebGridRow).Value as Person).Birthdate),
grid.Column(columnName: "Address.Physical.StreetNumber",
header: Html.DisplayFor(model => model.Address.Physical.StreetNumber)),
grid.Column(columnName: "Address.Physical.StreetName",
header: Html.DisplayFor(model => model.Address.Physical.StreetName))
)
)
这是一位同事向我提出的问题。我们广泛使用 WebGrid,并且必须为每一列重复输入相同的信息一式两份或一式三份……至少可以说是令人沮丧。我研究了扩展 WebGrid
本身,但似乎要使通用和 type-safe 需要大量工作。相反,我写了一个 HtmlHelper
扩展 returns a WebGridColumn
.
代码
public static WebGridColumn GridColumnFor<TModel, TValue>(this HtmlHelper<IEnumerable<TModel>> html, Expression<Func<TModel, TValue>> exp, string header = null, Func<dynamic, object> format = null, string style = null, bool canSort = true)
{
var metadata = ModelMetadata.FromLambdaExpression(exp, new ViewDataDictionary<TModel>());
var modelText = ExpressionHelper.GetExpressionText(exp);
if (format == null && metadata.DisplayFormatString != null)
{
format = (item) => string.Format(metadata.DisplayFormatString, item[modelText] ?? String.Empty);
}
return new WebGridColumn()
{
ColumnName = modelText,
Header = header ?? metadata.DisplayName ?? metadata.PropertyName ?? modelText.Split('.').Last(),
Style = style,
CanSort = canSort,
Format = format
};
}
任何您通常使用 WebGrid.Column()
的地方都可以使用 Html.GridColumnFor()
。
columns: grid.Columns(
Html.GridColumnFor(model => model.Name),
Html.GridColumnFor(model => model.Birthdate),
Html.GridColumnFor(model => model.Address.Physical.StreetNumber),
Html.GridColumnFor(model => model.Address.Physical.StreetName),
)
真漂亮...
怎么回事?
它使用 built-in 表达式功能获取完整的 属性 名称以传递给 WebGridColumn 构造函数,并从 MVC 获取已经 built-in 的元数据以获取要显示的名称headers,并检查格式。
它也接受 header 和格式值的覆盖,所以你可以自己设置它们;您可能希望一个人 object 用于多个页面,但有些人将 Birthdate
字段称为 "Birthday",而其他人可能将其称为 "Date of Birth"(我们尽量避免这种情况,但是有时这是最终用户的要求),或者只显示日期和月份:
Html.GridColumnFor(model => model.Birthdate, format: (item) => item.Birthdate.ToString("MM/dd"))
创建 WebGridColumn 时,需要为将要使用的 columnName 传入一个字符串。为什么它不允许像大多数其他 HTML 助手一样传递 lambda 表达式?我如何传递一个简单的 lambda 以获得智能提示、保留 type-safety 并防止因拼写错误导致的运行时错误?有了列名,WebGrid 难道不应该能够使用元数据显示属性来默认设置 header 和格式吗?
我们经常使用的东西:
@{ var grid = new WebGrid(model) }
@grid.GetHtml(
// table style formats here...
columns: grid.Columns(
grid.Column(columnName: "StudentName",
header: Html.DisplayNameFor(model => model.StudentName)),
grid.Column(columnName: "Birthdate",
header: Html.DisplayNameFor(model => model.Birthdate),
format: (item) => Html.DisplayFor(modelItem => (item as WebGridRow).Value as Person).Birthdate),
grid.Column(columnName: "Address.Physical.StreetNumber",
header: Html.DisplayFor(model => model.Address.Physical.StreetNumber)),
grid.Column(columnName: "Address.Physical.StreetName",
header: Html.DisplayFor(model => model.Address.Physical.StreetName))
)
)
这是一位同事向我提出的问题。我们广泛使用 WebGrid,并且必须为每一列重复输入相同的信息一式两份或一式三份……至少可以说是令人沮丧。我研究了扩展 WebGrid
本身,但似乎要使通用和 type-safe 需要大量工作。相反,我写了一个 HtmlHelper
扩展 returns a WebGridColumn
.
代码
public static WebGridColumn GridColumnFor<TModel, TValue>(this HtmlHelper<IEnumerable<TModel>> html, Expression<Func<TModel, TValue>> exp, string header = null, Func<dynamic, object> format = null, string style = null, bool canSort = true)
{
var metadata = ModelMetadata.FromLambdaExpression(exp, new ViewDataDictionary<TModel>());
var modelText = ExpressionHelper.GetExpressionText(exp);
if (format == null && metadata.DisplayFormatString != null)
{
format = (item) => string.Format(metadata.DisplayFormatString, item[modelText] ?? String.Empty);
}
return new WebGridColumn()
{
ColumnName = modelText,
Header = header ?? metadata.DisplayName ?? metadata.PropertyName ?? modelText.Split('.').Last(),
Style = style,
CanSort = canSort,
Format = format
};
}
任何您通常使用 WebGrid.Column()
的地方都可以使用 Html.GridColumnFor()
。
columns: grid.Columns(
Html.GridColumnFor(model => model.Name),
Html.GridColumnFor(model => model.Birthdate),
Html.GridColumnFor(model => model.Address.Physical.StreetNumber),
Html.GridColumnFor(model => model.Address.Physical.StreetName),
)
真漂亮...
怎么回事?
它使用 built-in 表达式功能获取完整的 属性 名称以传递给 WebGridColumn 构造函数,并从 MVC 获取已经 built-in 的元数据以获取要显示的名称headers,并检查格式。
它也接受 header 和格式值的覆盖,所以你可以自己设置它们;您可能希望一个人 object 用于多个页面,但有些人将 Birthdate
字段称为 "Birthday",而其他人可能将其称为 "Date of Birth"(我们尽量避免这种情况,但是有时这是最终用户的要求),或者只显示日期和月份:
Html.GridColumnFor(model => model.Birthdate, format: (item) => item.Birthdate.ToString("MM/dd"))