2013-11-04 48 views
2

我从数据库填充Dropdownlist,并且想通过设置其“class”属性以红色显示某些元素。所以,我尝试了很多方法,后来我为Dropdownlist创建了一个自定义HTML助手。但它没有任何意义,虽然它似乎添加了class属性,但此参数无法传递到Controller的Razor View。你能帮忙吗?为MVC4中的Dropdownlist的某些记录设置类属性

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' 后不包含“属性”的定义,也没有包含“接受类型的第一个参数”的扩展方法“属性”。因此,我认为我需要使用其他属性或帮助程序将类属性分配给自定义racords(对“if(record.Expired)” line)过滤记录没有问题。


查看:

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

你能澄清我怎么提供呢?提前致谢。



这里是具有两个类和禁用属性能力改性壳聚糖代码:

更新的代码(用于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"}) 


+0

退房这样的回答:[http://stackoverflow.com/a/7537628/674700](http://stackoverflow.com/a/7537628/674700)。 –

+0

这是一个静态列表,我认为该主题与我的问题没有太大关系。 –

+0

最简单的方法是连接文本属性与文本和类的东西像文本#类,然后在助手分裂它......从代码的角度来看它是不正确的..但这件事不会改变你现有的代码...如果将来你想添加更多的属性或乐趣,那么斯拉沃的答案是正确的...创建自定义的一个.. –

回答

2

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<CustomSelectItem>并通过它。在构建集合时,如果项目已过期,只需将Class属性设置为“disabled”或您正在使用的任何内容。下面是代码(我跳过了部分你在哪里得到的会议):

控制器:

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

感谢您的回复。但是,如果可以编辑包含View和Controller上的其他更改的回复(如果还需要Custom HTML helper)。 BR。 –

+0

我也尝试应用这个逻辑。但是我遇到了“无法将lambda表达式转换为'string'类型,因为它不是委托类型”错误。那么,你能否给我在View类中使用DDL和在新类中使用Helper方法?谢谢。 –

+0

我用代码更新了我的答案。 – Slavo

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>) 
+0

试图应用此逻辑,我遇到第一个“不能转换为类型'字符串',因为它不是一个委托类型的lambda表达式”,然后“扩展方法必须在非泛型静态类中定义”错误。在查找错误之后,我应用了关于论坛的所有建议,但是当我使用static关键字时,我得到了另一个错误。因此,您可以查看上面的代码,并给出一个示例,指出DropDownListHighlighted使用行的HTML Helper和View代码,如@ Html.DropDownListHighlighted(“meetingId”,ViewData [“MeetingId”]为MySelectListItem)。 –

+0

我在答案处添加了视图代码。请注意,该助手期待一个IEnumerable。 –

+0

关于第二个错误,您的扩展方法必须在静态类中定义(更多详细信息:[扩展方法](http://msdn.microsoft.com/en-us/library/vstudio/bb383977.aspx)。 –

相关问题