65.9K
CodeProject 正在变化。 阅读更多。
Home

MVC HtmlHelper: 文本发布下拉列表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (6投票s)

2012 年 2 月 3 日

CPOL

2分钟阅读

viewsIcon

33491

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" })

成功了!!就是这样,控件已准备好发布你的文本……

但别忘了发表你的评论!!:-)

© . All rights reserved.