【问题标题】:Set Class Attribute for certain records of Dropdownlist in MVC4为 MVC4 中 Dropdownlist 的某些记录设置类属性
【发布时间】:2013-11-12 02:16:52
【问题描述】:

我从数据库中填充下拉列表,我想通过设置它们的“类”属性以红色显示某些元素。所以,我尝试了很多方法,后来我为 Dropdownlist 创建了一个自定义 HTML Helper。但这没有任何意义,虽然它似乎是添加了类属性,但这个参数不能从 Controller 传递给 Razor View。你能帮忙吗?

MyHelper.cs:

public static MvcHtmlString Custom_DropdownList(this HtmlHelper helper, string name,  IEnumerable<SelectListItem> list, object htmlAttributes)
{        
    TagBuilder dropdown = new TagBuilder("select");
    dropdown.Attributes.Add("name", name);
    dropdown.Attributes.Add("id", name);
    StringBuilder options = new StringBuilder();
    foreach (var item in list)
    {            
        options = options.Append("<option value='" + item.Value + "'>" + item.Text + "</option>");
    }
    dropdown.InnerHtml = options.ToString();
    dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
    return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
}


控制器:

private void PopulateMeetingsDropDownList(object selectedMeetings = null)
{
    var meetingsQuery = repository.Meetings
    .Join(repository.Cities, m => m.MeetingCityId, c => c.CityID,
    (m, c) => new
    {
        CityID = c.CityID,
        CityName = c.CityName,
        MeetingDate = m.MeetingStartDate
    }
    )
    .OrderBy(x => x.CityID)
    .AsEnumerable()
    .Select(
    i => new
    {
        CityID = i.CityID,
        Name = string.Format(
        "{0} ({1:dd MMMM yyyy})",
        i.CityName, i.MeetingDate),
        Expired = i.MeetingDate < DateTime.UtcNow
    }
    ).ToList();

    var selectItems = new List<SelectListItem>(meetingsQuery.Count);
    foreach (var record in meetingsQuery)
    {
        var item = new SelectListItem
        {
            Text = record.Name,
            Value = record.Name
        };
        if (record.Expired)
        {
            item.Attributes.Add("class", "disabled"); //!!! Problem on this line
        }
            selectItems.Add(item);
    }
    ViewData["MeetingId"] = new SelectList(meetingsQuery, "CityID", "Name", selectedMeetings);
}  

但在应用此方法后,我收到错误“'System.Web.Mvc.SelectListItem' 不包含 'Attributes' 的定义,并且没有扩展方法 'Attributes' 接受类型的第一个参数......”。所以,我认为我需要使用另一个属性或助手将类属性分配给自定义 racords(在 "if (record.Expired)" 行过滤记录没有问题)。


查看:

@Html.Custom_DropdownList("MeetingId", ViewData["MeetingId"] as SelectList, new { id = "meetingId"})   

你能解释一下如何提供这个吗?提前致谢。



以下是修改后的代码,用于同时具备 Class 和 Disabled 属性:

更新的代码(用于 MyDropdownListFor):

自定义 HTML 助手类:

public static class MyHelpers
{
    public class MySelectItem : SelectListItem
    {
        public string Class { get; set; } 
        public string Disabled { get; set; }
    }

    public static MvcHtmlString MyDropdownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<MySelectItem> list, string optionLabel, object htmlAttributes)
    {
        return MyDropdownList(htmlHelper, ExpressionHelper.GetExpressionText(expression), list, optionLabel, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString MyDropdownList(this HtmlHelper htmlHelper, string name, IEnumerable<MySelectItem> list, string optionLabel, IDictionary<string, object> htmlAttributes)
    {
        TagBuilder dropdown = new TagBuilder("select");
        dropdown.Attributes.Add("name", name);
        dropdown.Attributes.Add("id", name);
        StringBuilder options = new StringBuilder();

        // Make optionLabel the first item that gets rendered.
        if (optionLabel != null)
            options = options.Append("<option value='" + String.Empty + "'>" + optionLabel + "</option>");

        foreach (var item in list)
        {
            if(item.Disabled == "disabled")
                options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "' disabled='" + item.Disabled + "'>" + item.Text + "</option>");
            else
                options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "'>" + item.Text + "</option>");
        }
        dropdown.InnerHtml = options.ToString();
        dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
        return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
    }
}


控制器:

    private void PopulateMeetingsDropDownList(object selectedMeetings = null)
    {
        var meetingsQuery = repository.Meetings
            .Join(repository.Cities, m => m.MeetingCityId, c => c.CityID,
                (m, c) => new
                {
                    CityID = c.CityID,
                    CityName = c.CityName,
                    MeetingDate = m.MeetingStartDate
                }
            )
            .OrderBy(x => x.CityID)
            .AsEnumerable()
            .Select(
                i => new
                {
                    Value = i.CityID.ToString(),
                    DisplayValue = string.Format(
                        "{0} ({1:dd MMMM yyyy})",
                        i.CityName, i.MeetingDate),
                    Expired = i.MeetingDate < DateTime.UtcNow
                }
            ).ToList();


        var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
        foreach (var record in meetingsQuery)
        {
            var item = new MyHelpers.MySelectItem
            {
                Text = record.DisplayValue,
                Value = record.Value
            };
            if (record.Expired)
            {
                item.Class = "disabled";
                item.Disabled = "disabled";
            }
            selectItems.Add(item);
        }
        ViewBag.MeetingData = selectItems;
    }


查看:

<label>Meeting</label>           
@Html.MyDropdownListFor(m => m.MeetingId, ViewBag.MeetingData as    List<MyHelpers.MySelectItem>, "---- Select ----", 
new { name = "meetingId", id = "meetingId"})  


【问题讨论】:

  • 这是一个静态列表,我认为该主题与我的问题无关。
  • 最简单的方法是将 text 属性与 text 和 class 连接起来,例如 text#class,然后在 helper 中拆分它......从代码的角度来看这是不对的......但这件事不会更改您现有的代码....如果将来您想添加更多属性或乐趣,那么 Slavo 的答案是正确的...创建自定义的..

标签: asp.net asp.net-mvc attributes html-helper html-select


【解决方案1】:

TL;DR;您正在使用SelectList,但您不需要。

创建一个新的视图模型类,您将把它传递给视图。它将包含您需要的所有属性,可能如下所示:

用于保存项目信息的自定义类:

public class CustomSelectItem
{
    public string Text {get;set;}
    public string Value {get;set;}
    public string Class {get;set;}
    public bool Selected {get;set;}
}

由于您使用 ViewData 传递此数据,因此您没有任何限制,您可以在其中放置任何内容。我建议您使用 ViewBag 而不是 ViewData。

在您的控制器中,您可以创建一个新的List&lt;CustomSelectItem&gt; 并传递它。构建集合时,如果项目已过期,只需将 Class 属性设置为“禁用”或您正在使用的任何内容。这是代码(我跳过了您获得会议的部分):

控制器:

var selectItems = new List<CustomSelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
    var item = new CustomSelectItem
    {
        Text = record.Name,
        Value = record.Name
    };
    if (record.Expired)
    {
        item.Class = "disabled";
    }
    selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;

然后修改您创建的自定义帮助器方法以接受CustomSelectItem 的集合而不是SelectListItem。您可以直接编写 HTML,因为您可以访问 Class 属性。

自定义辅助方法:

public static MvcHtmlString Custom_DropdownList(this HtmlHelper helper, string name, IList<CustomSelectItem> list, object htmlAttributes)
{
    TagBuilder dropdown = new TagBuilder("select");
    dropdown.Attributes.Add("name", name);
    dropdown.Attributes.Add("id", name);
    StringBuilder options = new StringBuilder();
    foreach (var item in list)
    {
        options = options.Append("<option value='" + item.Value + "' class='" + item.Class + "'>" + item.Text + "</option>");
    }
    dropdown.InnerHtml = options.ToString();
    dropdown.MergeAttributes(new RouteValueDictionary(htmlAttributes));
    return MvcHtmlString.Create(dropdown.ToString(TagRenderMode.Normal));
}

完成后,您可以从视图中调用帮助程序,如下所示:

查看:

@Html.Custom_DropdownList("MeetingId", ViewBag.MeetingData as List<CustomListItem>, new { id = "meetingId"})

【讨论】:

  • 感谢您的回复。但是,如果可能的话,您是否可以编辑包含 View 和 Controller 上的其他更改的回复(如果还需要自定义 HTML 帮助程序)。 BR。
  • 我也尝试应用这个逻辑。但是我遇到了“无法将 lambda 表达式转换为类型‘字符串’,因为它不是委托类型”错误。那么,你能告诉我 View 上的 DDL 和新类中的 Helper 方法的用法吗?谢谢。
  • 抱歉,回答晚了,我刚刚找到了应用您的代码的机会。正如您可能会看到上面最后更新的代码,我还在您的方法中添加了“禁用”属性。另一方面,我注意到您的方法不能使用 Html.DropDownListFor 或者我不能。 >>>
  • >>>非常感谢您的帮助和好方法,但如果您更新我的 last 更新代码,以便它可以与 Html.DropDownListFor 一起使用b> 在stackoverflow.com/questions/7536631/…stackoverflow.com/questions/16416498/… 页面点赞,我会选择你回复作为这个问题的答案。提前致谢。
【解决方案2】:

您可以继承 SelectList 并将自己的属性添加到类中,如下所示:

public class MySelectListItem : SelectListItem
{
    public bool Highlighted { get; set; }
}

一旦你有了自定义类,你就可以根据它编写你的助手。您可以应用不同的 css 类或更改样式属性。

public static class MyHtmlHelpers
{
    public static MvcHtmlString DropDownListHighlighted(this HtmlHelper helper, string name, IEnumerable<MySelectListItem> itens)
    {
        StringBuilder dropDown = new St();
        dropDown.AppendFormat("<select id='{0}' name='{0}'>", name);

        foreach (var item in itens)
        {
            dropDown.AppendFormat("<option selected='{2}' value='{1}' class='{3}'>{0}</option>",
                item.Text,
                item.Value,
                item.Selected ? "selected" : "",
                item.Highlighted ? "highlighted" : "normal");
        }

        dropDown.Append("</select>");

        return MvcHtmlString.Create(dropDown.ToString());
    }
}

在您的视图中(不要忘记在 web.config 或视图中添加 HTML 助手类的命名空间):

@Html.DropDownListHighlighted("DropDown", ViewData["DropDownOptions"] as List<MySelectListItem>)  

DropDownListHighlightedFor

你可以这样做来实现一个简单的 DropDownListHighlightedFor:

public static MvcHtmlString DropDownListHighlightedFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<MySelectListItem> itens)
{
    return DropDownListHighlighted(htmlHelper, ExpressionHelper.GetExpressionText(expression), itens);
}

在视图中:

@Html.DropDownListHighlightedFor(x => x.Option, ViewData["DropDownOptions"] as List<MySelectListItem>)

【讨论】:

  • 尝试应用这个逻辑我首先遇到“无法将 lambda 表达式转换为类型'字符串',因为它不是委托类型”,然后是“扩展方法必须在非泛型静态类中定义”错误。在查找错误后,我在论坛上应用了所有建议,但是当我使用静态关键字时,我又遇到了另一个错误。那么,您能否看一下上面的代码,并举例说明 DropDownListHighlighted 使用行的 HTML Helper 和 View 代码,例如 @Html.DropDownListHighlighted("meetingId", ViewData["MeetingId"] as MySelectListItem)。
  • 我在答案中添加了查看代码。请注意,帮助程序需要一个 IEnumerable。
  • 关于您的第二个错误,您的扩展方法必须在静态类中定义(更多详细信息:Extension Methods
  • 感谢您的帮助。实际上,我在 Slavo 之前已经先尝试过您的方法,但尽管它与另一种方法非常相似,但不幸的是它没有奏效。我试图纠正错误,但没有任何改变。尽管如此,我还是对您的回复投了赞成票,因为您的方法也非常有用。非常感谢。另一方面,由于 Html.DropDownListFor 没有其他答案的能力,我还没有决定完整的答案。 >>>
  • >>> 所以,如果你更新我的最后一个代码,以便它可以使用 DropDownlistFor 扩展方法,如 stackoverflow.com/questions/7536631/…stackoverflow.com/questions/16416498/… 页面,我会选择你的答案作为答案。在此先感谢...
猜你喜欢
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
相关资源
最近更新 更多