MVC HtmlHelper: 文本发布下拉列表






4.56/5 (6投票s)
HTML 帮助程序,它使下拉列表能够与其选定的文本一起发布值!!!
引言
大家知道,下拉列表只能将选定的值发布到服务器,而不能发布文本。在最近的项目中,我需要将下拉列表中选定的文本与选定的值一起提供。
大多数开发人员(包括我)首先想到的就是添加一个隐藏字段来发布文本,并在下拉列表更改时设置隐藏字段的值。是的,我做了同样的事情,但以一种更可重用的方式,我想与大家分享……
使用代码
仔细看看 Html Helper DropDownListFor
Html.DropDownListFor((m) => m.UserId, Model.UserCollection,
"--please select--", new { @style = "width:330px" })
我们缺少什么?嗯……我们只有指定下拉列表值的模型属性的选项。是的!这意味着我们需要一个额外的 Expression 参数来指定下拉列表的文本。所以,这是我们新的 Html Helper 的签名,带有一个额外的参数来键入文本模型属性。
internal static MvcHtmlString TextPostingDropDownListFor<TModel, TValProperty, TTextProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TValProperty>> valueExpression,
Expression<Func<TModel, TTextProperty>> textExpression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
IDictionary<string, object> htmlAttributes )
{
现在,正如我们决定的一样,我们将渲染一个隐藏控件与下拉列表一起,以保存文本。隐藏字段需要哪些属性?是的,你猜对了,Name、Id 和 Text。让我们先获取它们…
string textControlName =
htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName
(ExpressionHelper.GetExpressionText(textExpression));
string textControlId =
htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId
(ExpressionHelper.GetExpressionText(textExpression));
object text = ModelMetadata.FromLambdaExpression(textExpression, htmlHelper.ViewData).Model;
下一步是获取带有自定义属性和类的下拉列表的 HTML。为什么我们需要这些属性和类?嗯,这些是由我们的 jQuery 脚本用来设置控件的。
RouteValueDictionary attributes = new RouteValueDictionary(htmlAttributes);
if (attributes.ContainsKey("class"))
{
attributes["class"] = string.Format("{0} {1}", attributes["class"], "tpddl");
}
else
{
attributes.Add("class", "tpddl");
}
attributes.Add("tpddl-posting-control-id", textControlId);
MvcHtmlString html = htmlHelper.DropDownListFor(valueExpression, selectList, optionLabel, attributes);
你可以看到,我们添加了一个类 tpddl
和一个属性 tpddl-posting-control-id
,其值为文本控件的 ID。
现在我们需要隐藏控件了…
if (htmlAttributes.ContainsKey("class"))
htmlAttributes.Remove("class");
TagBuilder tb = new TagBuilder("input");
tb.MergeAttributes(htmlAttributes);
tb.MergeAttribute("name", textControlName);
tb.MergeAttribute("id", textControlId);
tb.MergeAttribute("type", "hidden");
tb.MergeAttribute("value", (text != null) ? text.ToString() : string.Empty);
让我们合并下拉列表和文本框 html 以获得最终结果。
string strHtml = string.Format("{0}{1}", html.ToHtmlString(), tb.ToString(TagRenderMode.SelfClosing));
return new MvcHtmlString(strHtml);
总而言之,最终代码如下。
internal static MvcHtmlString TextPostingDropDownListFor<TModel, TValProperty, TTextProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TValProperty>> valueExpression,
Expression<Func<TModel, TTextProperty>> textExpression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
IDictionary<string, object> htmlAttributes)
{
string textControlName =
htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName
(ExpressionHelper.GetExpressionText(textExpression));
string textControlId =
htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId
(ExpressionHelper.GetExpressionText(textExpression));
object text = ModelMetadata.FromLambdaExpression(textExpression, htmlHelper.ViewData).Model;
RouteValueDictionary attributes = new RouteValueDictionary(htmlAttributes);
if (attributes.ContainsKey("class"))
{
attributes["class"] = string.Format("{0} {1}", attributes["class"], "tpddl");
}
else
{
attributes.Add("class", "tpddl");
}
attributes.Add("tpddl-posting-control-id", textControlId);
MvcHtmlString html = htmlHelper.DropDownListFor(valueExpression,
selectList, optionLabel, attributes);
if (htmlAttributes.ContainsKey("class"))
htmlAttributes.Remove("class");
TagBuilder tb = new TagBuilder("input");
tb.MergeAttributes(htmlAttributes);
tb.MergeAttribute("name", textControlName);
tb.MergeAttribute("id", textControlId);
tb.MergeAttribute("type", "hidden");
tb.MergeAttribute("value", (text != null) ? text.ToString() : string.Empty);
string strHtml = string.Format("{0}{1}", html.ToHtmlString(),
tb.ToString(TagRenderMode.SelfClosing));
return new MvcHtmlString(strHtml);
}
现在你可以添加一些公共重载,以方便用户使用。
public static MvcHtmlString TextPostingDropDownListFor<TModel, TProperty, TTextProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> valueExpression,
Expression<Func<TModel, TTextProperty>> textExpression,
IEnumerable<SelectListItem> selectList)
{
var attributes = new RouteValueDictionary();
return htmlHelper.TextPostingDropDownListFor(
valueExpression,
textExpression,
selectList,
null,
attributes);
}
public static MvcHtmlString TextPostingDropDownListFor<TModel, TProperty, TTextProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> valueExpression,
Expression<Func<TModel, TTextProperty>> textExpression,
IEnumerable<SelectListItem> selectList,
string optionLabel)
{
var attributes = new RouteValueDictionary();
return htmlHelper.TextPostingDropDownListFor(
valueExpression,
textExpression,
selectList,
optionLabel,
attributes);
}
public static MvcHtmlString CMSTextPostingDropDownListFor<TModel, TProperty, TTextProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> valueExpression,
Expression<Func<TModel, TTextProperty>> textExpression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
object htmlAttributes)
{
var attributes = new RouteValueDictionary(htmlAttributes);
return htmlHelper.TextPostingDropDownListFor(
valueExpression,
textExpression,
selectList,
optionLabel,
attributes);
}
接下来,我将添加 jQuery 脚本以使控件正常工作。添加一个脚本文件,例如 textpostingdropdown.js,并将以下代码添加到其中。
$(document).ready(function () {
$(".tpddl").setTextPostingDropdown();
}
jQuery.fn.setTextPostingDropdown = function () {
$(this).each(function () {
$(this).makeDropdownTextPostable();
});
}
jQuery.fn.makeDropdownTextPostable = function () {
$(this).bind("change", function () {
var textcontrolid = $(this).attr("tpddl-posting-control-id");
var selText = $(this).find("option:selected").text();
$("#" + textcontrolid).val(selText);
});
};
通过指定下拉列表文本的模型属性,使用该控件,如下所示。
Html.TextPostingDropDownListFor((m) => m.UserId,(m) => m.UserName,
Model.UserCollection, "--please select--", new { @style = "width:330px" })
成功了!!就是这样,控件已准备好发布你的文本……
但别忘了发表你的评论!!:-)