次のように、ドロップダウンリストにタイトルタグを配置するために多くの時間を使用するHtmlHelper式を作成しました。
public static HtmlString SelectFor<TModel, TProperty, TListItem>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<TListItem> enumeratedItems,
string idPropertyName,
string displayPropertyName,
string titlePropertyName,
object htmlAttributes) where TModel : class
{
//initialize values
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var propertyName = metaData.PropertyName;
var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
var enumeratedType = typeof(TListItem);
//build the select tag
var returnText = string.Format("<select id=\"{0}\" name=\"{0}\"", HttpUtility.HtmlEncode(propertyName));
if (htmlAttributes != null)
{
foreach (var kvp in htmlAttributes.GetType().GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
{
returnText += string.Format(" {0}=\"{1}\"", HttpUtility.HtmlEncode(kvp.Key),
HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
}
}
returnText += ">\n";
//build the options tags
foreach (TListItem listItem in enumeratedItems)
{
var idValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == idPropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
var titleValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == titlePropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
var displayValue = enumeratedType.GetProperties()
.FirstOrDefault(p => p.Name == displayPropertyName)
.GetValue(listItem, null).ToStringOrEmpty();
returnText += string.Format("<option value=\"{0}\" title=\"{1}\"",
HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
if (idValue == propertyValue)
{
returnText += " selected=\"selected\"";
}
returnText += string.Format(">{0}</option>\n", displayValue);
}
//close the select tag
returnText += "</select>";
return new HtmlString(returnText);
}
...これは水泳で機能しますが、さらに進みたい場合があります。HTMLを書き出さずに、この獣のID、表示、タイトルをカスタマイズしたいと思います。たとえば、次のようなモデルにいくつかのクラスがある場合:
public class item
{
public int itemId { get; set; }
public string itemName { get; set; }
public string itemDescription { get; set; }
}
public class model
{
public IEnumerable<item> items { get; set; }
public int itemId { get; set; }
}
私の見解では、私は次のように書くことができます。
@Html.SelectFor(m => m.itemId, Model.items, "itemId", "itemName", "itemDescription", null)
...そして、タイトル属性などの素敵なドロップダウンが表示されます。これは、列挙されたアイテムに、表示したいプロパティが正確に含まれている限り、すばらしいものです。しかし、私が本当にやりたいことは次のようなものです。
@Html.SelectFor(m => m.itemId, Model.items, id=>id.itemId, disp=>disp.itemName, title=>title.itemName + " " + title.itemDescription, null)
...そして、この場合、オプションのtitle属性は、itemName
プロパティとプロパティの連結ですitemDescription
。私はラムダ式のメタレベルを告白し、Linq関数は私を少しめまいにさせました。誰かが私を正しい方向に向けることができますか?
最終結果興味のある人のために、次のコードを使用すると、ラムダ式を使用して、選択リストのID、Title、およびDisplayTextプロパティを完全に制御できます。
public static HtmlString SelectFor<TModel, TProperty, TListItem>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> forExpression,
IEnumerable<TListItem> enumeratedItems,
Attribute<TListItem> idExpression,
Attribute<TListItem> displayExpression,
Attribute<TListItem> titleExpression,
object htmlAttributes,
bool blankFirstLine) where TModel : class
{
//initialize values
var metaData = ModelMetadata.FromLambdaExpression(forExpression, htmlHelper.ViewData);
var propertyName = metaData.PropertyName;
var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
var enumeratedType = typeof(TListItem);
//build the select tag
var returnText = string.Format("<select id=\"{0}\" name=\"{0}\"", HttpUtility.HtmlEncode(propertyName));
if (htmlAttributes != null)
{
foreach (var kvp in htmlAttributes.GetType().GetProperties()
.ToDictionary(p => p.Name, p => p.GetValue(htmlAttributes, null)))
{
returnText += string.Format(" {0}=\"{1}\"", HttpUtility.HtmlEncode(kvp.Key),
HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
}
}
returnText += ">\n";
if (blankFirstLine)
{
returnText += "<option value=\"\"></option>";
}
//build the options tags
foreach (TListItem listItem in enumeratedItems)
{
var idValue = idExpression(listItem).ToStringOrEmpty();
var displayValue = displayExpression(listItem).ToStringOrEmpty();
var titleValue = titleExpression(listItem).ToStringOrEmpty();
returnText += string.Format("<option value=\"{0}\" title=\"{1}\"",
HttpUtility.HtmlEncode(idValue), HttpUtility.HtmlEncode(titleValue));
if (idValue == propertyValue)
{
returnText += " selected=\"selected\"";
}
returnText += string.Format(">{0}</option>\n", displayValue);
}
//close the select tag
returnText += "</select>";
return new HtmlString(returnText);
}
public delegate object Attribute<T>(T listItem);