ASP MVC 5 C# 递归树分组和缩进 DropDownList

ASP MVC 5 C# Recursive Trees To Group and Indent A DropDownList

我有一个名为 Category 的模型,它具有如下递归 (parent child) 关系:

public class Category: ITreeNode<Category>
    {
        public byte Id { get; set; }
        public byte? ParentId { get; set; }
        public string Name { get; set; }

        public Category Parent { get; set; }
        public IList<Category> Children { get; set; }

    }

我想生成一个基于 parent child 关系的 heirachaly 分组的下拉列表,我也可以 select parent 组如下 - 基本上我想从 parent:

中缩进 children
 <select name="Category" id="Category">
       <option value="0">All</option>
       <option value="1">Cars</option>
       <option value="2">--Toyota</option>
       <option value="3">--Nissan</option>
       <option value="4">Fruits</option>
       <option value="5">--Apples</option>
       <option value="6">--Oranges</option>
    </select>

我的Table数据如下:

 Id  | ParentId  | Name
 ----------------------
 1   |   null    |  Cars
 2   |   1       |  Toyota
 3   |   1       |  Nissan
 4   |   null    |  Fruits
 5   |   4       |  Apples
 6   |   4       |  Oranges

目前我有以下 LINQ 查询,但它只是生成一个按 id 排序的普通下拉列表。

    public IEnumerable<SelectListItem> GetCategoriesSelectList()
    {
        var categories = new List<SelectListItem>
            {
                new SelectListItem() {Value = "0", Text = "All" }

            }.Concat(_context.Category.Select(x => new SelectListItem
            {
                Value = x.Id.ToString(),
                Text = x.Name
            }).OrderBy(x => x.Value).ToList());

        return categories
    }

我如何修改 LINQ 查询以在使用 Html.DropDownListFor.

呈现时正确分组和缩进

我试图修改我原来的 select 列表来实现某种树,如下所示,但我被困在 EnumerateNodes 方法上。下面的原件用于打印我从以下站点 http://www.codeproject.com/Articles/23949/Building-Trees-from-Lists-in-NET 提取的 ul 列表。我如何遍历它和 return 每个项目,如果它是 child 然后将 -- 附加到名称并添加到我的 select 列表?

   public IEnumerable<SelectListItem> GetCategoriesSelectList()
    {
        IList<Category> listOfNodes = GetListOfNodes();
        IList<Category> topLevelCategories = TreeHelper.ConvertTOForest(listOfNodes);

       var cats = new List<SelectListItem> 
       { 
            new SelectListItem { Value = "0", Text = "All"} 
       };

       foreach(var category in topLevelCategories) {
            var catName = EnumerateNodes(category);
            cats.Add(new SelectListItem { Value = category.Id.ToString(), Text = catName });
       }
        return cats;
    }

    private List<Category> GetListOfNodes()
   {

    List<Category> sourceCategories = _context.Category.ToList();
    List<Category> categories = new List<Category>();
    foreach (Category sourceCategory in sourceCategories)
    {
      Category s = new Category();
      s.Id = sourceCategory.Id;
      s.Name = sourceCategory.Name;
      if (sourceCategory.ParentId != null)
      {
          s.Parent = new Category();
          s.Parent.Id = (int)sourceCategory.ParentId;
      }
      categories.Add(s);
    }
    return categories;
  }

 private static string EnumerateNodes(Category parent)
{
   if (category.Children.Count > 0) {
      Response.Write("<ul>");
      foreach(Category child in category.Children) {
          EnumerateNodes(child);
      }
      Response.Write("</ul>");
   }
   Response.Write("</li>");
}

您可以先 select 父类别(其中 ParentIdnull),然后对于每个父类别,select 它的子类别。

public IEnumerable<SelectListItem> GetCategoriesSelectList()
{
    var categories = _context.Category.ToList();
    // Initialise list and add first "All" item
    List<SelectListItem> options = new List<SelectListItem>
    {
        new SelectListItem(){ Value = "0", Text = "All" }
    };
    // Get the top level parents
    var parents = categories.Where(x => x.ParentId == null);
    foreach (var parent in parents)
    {
        // Add SelectListItem for the parent
        options.Add(new SelectListItem()
        {
            Value = parent.Id.ToString(),
            Text = parent.Name
        });
        // Get the child items associated with the parent
        var children = categories.Where(x => x.ParentId == parent.Id);
        // Add SelectListItem for each child
        foreach (var child in children)
        {
            options.Add(new SelectListItem()
            { 
                Value = child.Id.ToString(),
                Text = string.Format("--{0}",child.Name)
            });
        }
    }
    return options;
}

您需要递归调用类别,以便在需要时获得无限级嵌套。上面提到的代码仅适用于 2 层嵌套,因此您在这里只有 2 层:父级和子级。 以将 categoryId 作为参数并且递归函数将 categoryId 作为 parentId 的方式创建函数,这样您就可以更深入地进入树的另一个级别,但最终您可以让新类别成为另一个类别的父类别类别。