缩进的SelectList项

时间:2012-03-28 10:43:40

标签: asp.net-mvc indentation selectlist

我有一个类别列表(实体),每个类别都有父母。以下是该类别的模型:

  public class Category
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CategoryId { get; set; }

        public int? ParentId { get; set; }
        public string Name { get; set; }

        public virtual Category Parent { get; set; }
    }

我需要填充一个SelectList,这样父母就会先来,而孩子们会缩进像:

        
  • 第1类       
    • SubCategory 1
    •           
    • SubCategory 2
    •       
        
  •     
  • 第2类

我必须使用此选择列表来编辑编辑和更新表单中的下拉列表。我该怎么做呢?客户端?服务器端?

感谢您提供的任何帮助。

2 个答案:

答案 0 :(得分:3)

这让我想到在没有interface的依赖的情况下实现它,我仍然认为这是合理的。这是使用扩展方法的替代解决方案,不需要实现interface

扩展方法

public static class ExtensionMethods
{
    /// <summary>
    /// Returns a single-selection select element containing the options specified in the items parameter.
    /// </summary>
    /// <typeparam name="T">The type of elements in the collection.</typeparam>
    /// <param name="helper">The class being extended.</param>
    /// <param name="items">The collection of items used to populate the drop down list.</param>
    /// <param name="parentItemsPredicate">A function to determine which elements are considered as parents.</param>
    /// <param name="parentChildAssociationPredicate">A function to determine the children of a given parent.</param>
    /// <param name="dataValueField">The value for the element.</param>
    /// <param name="dataTextField">The display text for the value.</param>
    /// <returns></returns>
    public static MvcHtmlString DropDownGroupList<T>(
        this HtmlHelper helper,
        IEnumerable<T> items,
        Func<T, bool> parentItemsPredicate,
        Func<T, T, bool> parentChildAssociationPredicate,
        string dataValueField,
        string dataTextField)
    {
        var html = new StringBuilder("<select>");

        foreach (var item in items.Where(parentItemsPredicate))
        {
            html.Append(string.Format("<optgroup label=\"{0}\">", item.GetType().GetProperty(dataTextField).GetValue(item, null)));

            foreach (var child in items.Where(x => parentChildAssociationPredicate(x, item)))
            {
                var childType = child.GetType();

                html.Append(string.Format("<option value=\"{0}\">{1}</option>", childType.GetProperty(dataValueField).GetValue(child, null), childType.GetProperty(dataTextField).GetValue(child, null)));
            }

            html.Append("</optgroup>");
        }

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

        return new MvcHtmlString(html.ToString());
    }
}
根据您的Category class

用法

@this.Html.DropDownGroupList(YourCollection, x => !x.ParentId.HasValue, (x, y) => { return x.ParentId.Equals(y.CategoryId); }, "CategoryId", "Name")

当我写完这篇文章的时候,我不太确定这有什么价值,但我想我还是会发布它。

如您所见,您的class必须知道其父级的ID,并且子级和父级的显示名称应使用dataTextField参数指示的相同属性。因此,基本上,您的class需要属性:Id,ParentId和Name,您可以使用Func<T, bool>Func<T, T, bool>参数来确定关系。

不要忘记添加必要的验证!

答案 1 :(得分:1)

我会在optgroup语法中使用razor这样做服务器端。

<select>
@foreach(var parent in categories.Where(x => !x.ParentId.HasValue)
{
    <optgroup label="@parent.Name">
    @foreach(var child in categories.Where(x => x.ParentId.Equals(parent.CategoryId))
    {
        <option value="@child.CategoryId">@child.Name</option>
    }
    </optgroup>
}
</select>

我还会将其作为扩展方法,因此它需要其他可用的HTML帮助程序方法。

修改


扩展方法可以接受实现如下简单界面的项集合:

public interface IGroupable
{
    int Id { get; set; }

    string Name { get; set; }

    int? ParentId { get; set; }
}

public class Category : IGroupable
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CategoryId { get; set; }

    public int? ParentId { get; set; }    //implements IGroupable.ParentId
    public string Name { get; set; }    //implements IGroupable.Name

    public virtual Category Parent { get; set; }

    #region [IGroupable Specific  Implementation]

    public int Id { get { return this.CategoryId; } }

    #endregion
}

public static class ExtensionMethods
{
    public static MvcHtmlString DropDownGroupList(this HtmlHelper helper, IEnumerable<IGroupable> items)
    {
        var html = new StringBuilder("<select>");

        foreach (var item in items.Where(x => !x.ParentId.HasValue))
        {
            html.Append(string.Format("<optgroup label=\"{0}\">", item.Name));

            foreach(var child in items.Where(x => x.ParentId.Equals(item.Id)))
            {
                html.Append(string.Format("<option value=\"{0}\">{1}</option>", child.Id, child.Name));
            }

            html.Append("</optgroup>");
        }

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

        return new MvcHtmlString(html.ToString());
    }
}