tôi đã viết một biểu thức HtmlHelper tôi sử dụng rất nhiều thời gian để đưa các thẻ tiêu đề vào danh sách thả xuống của tôi như vậy:Fun với LINQ Expressions trong phương pháp khuyến nông
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);
}
... này làm việc thuận buồm xuôi, nhưng có những lúc tôi muốn đi xa hơn. Tôi muốn tùy chỉnh các phần id, hiển thị và tiêu đề của con thú này mà không cần phải viết ra html. Ví dụ, nếu tôi có một số lớp học trong một mô hình như vậy:
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; }
}
Theo quan điểm của tôi, tôi có thể viết:
@Html.SelectFor(m => m.itemId, Model.items, "itemId", "itemName", "itemDescription", null)
... và tôi sẽ nhận được một danh sách lí tốt đẹp với các thuộc tính tiêu đề vv Điều này là tuyệt vời miễn là các mục được liệt kê có các thuộc tính chính xác như tôi muốn hiển thị chúng. Nhưng những gì tôi thực sự muốn làm là một cái gì đó như:
@Html.SelectFor(m => m.itemId, Model.items, id=>id.itemId, disp=>disp.itemName, title=>title.itemName + " " + title.itemDescription, null)
... và có, trong trường hợp này, các thuộc tính tiêu đề trên các tùy chọn là một nối của itemName
bất động sản và các itemDescription
tài sản. Tôi thú nhận siêu mức của các biểu thức lambda và các hàm LINQ đã khiến tôi hơi chóng mặt. Ai đó có thể chỉ cho tôi đi đúng hướng?
CUỐI CÙNG KẾT QUẢ Đối với những người tò mò, đoạn code sau mang lại cho tôi toàn quyền điều khiển ID, tài sản Tiêu đề, và DisplayText sự chọn danh sách bằng cách sử dụng các biểu thức lambda:
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);
LƯU Ý: các ToStringOrEmpty() mở rộng là phương pháp của tôi mà phải mất một đối tượng và thực hiện một ToString() trên nó trừ khi nó là null, trong trường hợp nó mang lại một chuỗi rỗng. –