1

这是 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>

4

1 回答 1

0

您不需要 HtmlHelper,您实际需要的只是一种将DropdownTreeview对象图转换为IEnumerable<SelectListItem>可以传递到现有DropDownForHtmlHelper 以及(可以说是优越的)SelectTagHelper(aka <select asp-items>)的方法。


因为您的class DropdownTreeview项目不包含对父项目的任何对象引用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()到 into asp-items,如下所示:

@model MyPageViewModel

TreeNode[] nodes = this.Model.TreeNodes;

TreeGraph graph = new TreeGraph( nodes );

//

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

于 2021-12-26T15:18:39.307 回答