【问题标题】:ASP MVC 5 C# Recursive Trees To Group and Indent A DropDownListASP MVC 5 C# 递归树对 DropDownList 进行分组和缩进
【发布时间】:2016-07-21 17:48:41
【问题描述】:

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

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; }

    }

我想生成一个下拉列表,该下拉列表根据父子关系进行分组,我还可以按如下方式选择父组 - 基本上我想从父级缩进子级:

 <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 呈现时正确分组和缩进。

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

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

【问题讨论】:

标签: c# linq asp.net-mvc-5 html.dropdownlistfor recursive-query


【解决方案1】:

您可以先选择父类别(其中ParentIdnull),然后为每个父类别选择其子类别。

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;
}

【讨论】:

  • 我在以下行 foreach (var child in children) 上收到错误 There is already an open DataReader associated with this Command which must be closed first.。为了解决这个问题,我将var categories = _context.Category; 修改为var categories = _context.Category.ToList()var children = products.Where(x =&gt; x.ParentId == parent.Id); 这行还有一个错字,应该是var children = categories.Where(x =&gt; x.ParentId == parent.Id); 如果您修改答案,我可以将其标记为解决方案。干杯。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2021-10-20
    • 2020-12-22
    • 2011-02-18
    • 2016-10-28
    • 2016-10-07
    • 1970-01-01
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多