【问题标题】:How to Create Custom HTML Helper for dropdown tree list in asp.net core 6?如何在 asp.net core 6 中为下拉树列表创建自定义 HTML 助手?
【发布时间】:2021-12-24 16:36:32
【问题描述】:

这是 html 源代码中的下拉列表示例。我想为此创建一个 html 助手,以使用带有选择选项的通用树列表选项! 例如,每一层都只显示这样的嵌套文本:A > A1 > A11。


我的模型

DropdownTreeview{
        public long Id { get; set; }
        public long? IdParent { get; set; }
        public string Name { get; set; }
}

<select class="form-control valid" data-val="true" data-val-required="The Parent category field is required." id="ParentCategoryId" name="ParentCategoryId" aria-describedby="ParentCategoryId-error" aria-invalid="false"><option selected="selected" value="0">[None]</option>
<option value="1">Computers</option>
<option value="2">Computers > Desktops</option>
<option value="3">Computers > Notebooks</option>
<option value="4">Computers > Software</option>
<option value="5">Electronics</option>
<option value="6">Electronics > Camera photo</option>
<option value="7">Electronics > Cell phones</option>
<option value="8">Electronics > Others</option>
<option value="9">Apparel</option>
<option value="10">Apparel > Shoes</option>
<option value="11">Apparel > Clothing</option>
<option value="12">Apparel > Clothing  > Shirt</option>
<option value="13">Apparel > Clothing  > TShirt</option>
<option value="14">Apparel > Accessories</option>
<option value="15">downloads</option>
<option value="16">Books</option>
<option value="17">Jewelry</option>
<option value="18">Gift Cards</option>
</select>

【问题讨论】:

  • 网络上没有“下拉树视图”之类的东西。请更具体地说明您想要实现的目标,并为您的努力提供不仅仅是预先呈现的&lt;select&gt;
  • 我想将层次结构模型 (IdParent) 传递给自定义 HTML 帮助器,以便像树一样为每个级别添加“-”并显示带有许多选项的选择。
  • 原生 HTML 元素无法做到这一点:&lt;select&gt; 元素仅支持通过 &lt;optgroup&gt; 进行的最多 2 级嵌套。
  • 我的意思是每个级别只显示这样的嵌套文本:A > A1 > A11。

标签: .net-core html-helper asp.net-core-6.0


【解决方案1】:

您不需要 HtmlHelper,您真正需要的只是一种将 DropdownTreeview 对象图转换为 IEnumerable&lt;SelectListItem&gt; 的方法,您可以将其传递到现有的 DropDownFor HtmlHelper 以及 (可以说是优越)SelectTagHelper(又名&lt;select asp-items&gt;)。


因为您的 class DropdownTreeview 项目不包含任何 object-references 到父 class DropdownTreeview 项目(而不是您使用 long? IdParent),所以您不能使用现有的直接方法来遍历图形。在我的方法中,我将这些转换为可遍历的对象图,然后可以将其展平为 SelectListItem 对象列表。

我要将您的 class DropdownTreeview 重命名为 class TreeNode,因为每个实例代表一个节点,而不是整个树。

您可以直接将其复制并粘贴到 Linqpad 中以查看它运行(当然,您需要添加对 ASP.NET Core 的 NuGet 引用才能使用 SelectListItem):

void Main()
{
    TreeNode[] initialNodes = new[]
    {
        new TreeNode(  1, null, "Computers" ),
        new TreeNode(  2,    1, "Desktops" ),
        new TreeNode(  3,    1, "Notebooks" ),
        new TreeNode(  4,    1, "Software" ),
        new TreeNode(  5, null, "Electronics" ),
        new TreeNode(  6,    5, "Camera photo" ),
        new TreeNode(  7,    5, "Cell phones" ),
        new TreeNode(  8,    5, "Others" ),
        new TreeNode(  9, null, "Apparel" ),
        new TreeNode( 10,    9, "Shoes" ),
        new TreeNode( 11,    9, "Clothing" ),
        new TreeNode( 12,   11, "Shirt" ),
        new TreeNode( 13,   11, "TShirt" ),
        new TreeNode( 14,    9, "Accessories" ),
        new TreeNode( 15, null, "Downloads" ),
        new TreeNode( 16, null, "Books" ),
        new TreeNode( 17, null, "Jewelry" ),
        new TreeNode( 18, null, "Gift Cards" )
    };
    
    TreeGraph graph = new TreeGraph( initialNodes );
    
//  graph.EnumerateDepthFirst().Dump();
    graph.AsSelectListItems().Dump();
}

public record TreeNode( Int64 id, Int64? parentId, String name );

public class TreeGraph
{
    private readonly IReadOnlyDictionary<Int64,( TreeNode node, List<TreeNode> children )> nodesById;
    
    public TreeGraph( IEnumerable<TreeNode> initialNodes )
    {
        Dictionary<Int64,( TreeNode node, List<TreeNode> children )> nodesByIdMut = initialNodes
            .ToDictionary( n => n.id, n => ( node: n, children:  new List<TreeNode>() ) );
        
        foreach( TreeNode child in initialNodes.Where( n => n.parentId.HasValue ) )
        {
            nodesByIdMut[ child.parentId!.Value ].children.Add( child );
        }
        
        this.nodesById = nodesByIdMut;
    }
    
    private String GetPath( TreeNode node )
    {
        if( node.parentId == null ) return node.name;
        
        Stack<TreeNode> stack = new Stack<TreeNode>();
        
        TreeNode? n = node;
        while( n != null )
        {
            stack.Push( n );
            
            n = n.parentId.HasValue ? ( nodesById[ n.parentId.Value ].node ) : null;
        }
        
        return String.Join( separator: " > ", stack.Select( n2 => n2.name ) );
    }
    
    private IEnumerable<TreeNode> GetRoots()
    {
        return this.nodesById.Values
            .Where( t => t.node.parentId == null )
            .OrderBy( t => t.node.name )
            .Select( t => t.node );
    }
    
    private IEnumerable<TreeNode> GetChildren( TreeNode node )
    {
        return this.nodesById[ node.id ].children;
    }
    
    public IEnumerable<( TreeNode n, String path )> EnumerateDepthFirst()
    {
        foreach( TreeNode root in this.GetRoots() )
        {
            foreach( ( TreeNode descendant, String path ) pair in this.EnumerateDepthFirstFrom( root ) )
            {
                yield return pair;
            }
        }
    }
    
    private IEnumerable<( TreeNode n, String path )> EnumerateDepthFirstFrom( TreeNode root )
    {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.Push( root );
        
        while( stack.Count > 0 )
        {
            TreeNode n = stack.Pop();
            foreach( TreeNode c in this.GetChildren( n ) )
            {
                stack.Push( c );
            }
            
            String path = this.GetPath( n );
            
            yield return ( n, path );
        }
    }
    
    public IEnumerable<SelectListItem> AsSelectListItems()
    {
        return this.EnumerateDepthFirst()
            .Select( pair => new SelectListItem()
            {
                Text  = pair.path,
                Value = pair.n.id.ToString( CultureInfo.InvariantCulture )
            } )
    }
}

截图证明:


要在 Razor (.cshtml) 视图中使用它,请在某处实例化 TreeGraph 并将 AsSelectListItems() 的结果传递给 asp-items,如下所示:

@model MyPageViewModel

TreeNode[] nodes = this.Model.TreeNodes;

TreeGraph graph = new TreeGraph( nodes );

//

<form>
    
    <select asp-items="@( graph.AsSelectListItems() )"></select>
    
</form>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-07
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 2018-10-05
    相关资源
    最近更新 更多