从 C# 中的分层数据创建 HTML 无序列表
Create HTML unordered list from hierarchical data in C#
我正在尝试根据分层数据编写一个基本的 HTML 无序列表。数据如下所示:
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
}
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
以下是我试图根据上述数据创建的内容:
<ul>
<li>Top task
<ul>
<li>Subtask 1
<ul>
<li>Subtask 2</li>
</ul>
</li>
</ul>
<ul>
<li>Subtask 3
<ul>
<li>Subtask 4</li>
</ul>
</li>
</ul>
</li>
</ul>
我尝试了以下帖子并取得了一些成功:
Return unordered list from hierarchical sql data 和
C# Create HTML unordered list from List using Recursion
这是我从上面的第一个 link 改编而来的代码,它大部分都有效,但是如果更改了分层数据的顺序,该方法会在第一个不是 child 的前一个 parent。例如,如果我按如下方式更改数据列表的顺序,它将跳过子任务 1 和 2:
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
public Task FindTask( int id )
{
return FindTask( this, id );
}
private Task FindTask( Task task, int id )
{
if( task.Id == id )
{
return task;
}
Task returnTask = null;
foreach( Task child in task.Tasks )
{
returnTask = child.FindTask( id );
if( returnTask != null )
{
break;
}
}
return returnTask;
}
}
List<Task> topTasks = new List<Task>( );
protected void GetHierarchy( int id )
{
List<Task> data = new List<Task>( );
data.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
data.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
data.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
data.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
data.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
foreach( var row in data )
{
Task tasks = new Task( );
tasks.Title = row.Title;
tasks.Id = row.Id;
if( row.ParentId == null )
{
topTasks.Add( tasks );
}
else
{
int parentId = row.ParentId.Value;
foreach( Task topTask in topTasks )
{
Task parentTask = topTask.FindTask( parentId );
if( parentTask != null )
{
parentTask.Tasks.Add( tasks );
break;
}
}
}
}
}
protected string Render( )
{
var s = new StringBuilder( );
GetHierarchy( id );
s.Append( "<ul>" );
foreach( Task child in topTasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
return s.ToString( );
}
private void RenderTask( StringBuilder s, Task task )
{
s.Append( "<li>" );
s.Append( task.Title );
if( task.Tasks.Count > 0 )
{
s.Append( "<ul>" );
foreach( Task child in task.Tasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}
我不想使用 jquery 树视图或任何其他组件,因为这需要一个独立的解决方案。
任何人都可以建议我更好的方法,或者至少帮助我修复我在上面实现的代码,以便数据的顺序不会破坏递归?
提前致谢。
在您的 GetHierarchy 函数中,您将按顺序循环访问列表中的每个任务。如果列表中的第一个任务的 parentId 为空,那么它将被添加到 topTasks 列表中。
但是,如果第一个任务有一个非空的 parentId,那么它将被添加到 topTasks 中的父任务。请注意,这里的父任务还不存在于 topTasks 列表中,因此不会插入该任务。
我会使用一个递归函数,它首先获取具有空父项的任务,然后使用该任务的 ID 递归调用该函数,直到它到达树的底部。
一个粗略的例子:
Task addSubLists (List<Task> data, Task parent) {
foreach(Task task in data) {
if (task.parentId.Value == parent.Id.Value) {
parent.Tasks.Add(addSubLists(data, task));
}
}
return parent;
}
您将顶级任务传递给函数,它会添加所有后代。
最后,我改编了C# Create HTML unordered list from List using Recursion的答案,效果很好。这是我使用的代码:
protected string WriteList( )
{
var s = new StringBuilder( );
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
s.Append( "<ul>" );
foreach( var task in tasks )
{
if( task.ParentId == null )
{
WriteTaskList( tasks, task, s );
}
}
s.Append( "</ul>" );
return s.ToString( );
}
private static void WriteTaskList( List<Task> tasks, Task task, StringBuilder s )
{
s.Append( "<li>" + task.Title );
var subtasks = tasks.Where( p => p.ParentId == task.Id );
if( subtasks.Count( ) > 0 )
{
s.Append( "<ul>" );
foreach( Task p in subtasks )
{
if( tasks.Count( x => x.ParentId == p.Id ) > 0 )
WriteTaskList( tasks, p, s );
else
s.Append( string.Format( "<li>{0}</li>", p.Title ) );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}
我正在尝试根据分层数据编写一个基本的 HTML 无序列表。数据如下所示:
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
}
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
以下是我试图根据上述数据创建的内容:
<ul>
<li>Top task
<ul>
<li>Subtask 1
<ul>
<li>Subtask 2</li>
</ul>
</li>
</ul>
<ul>
<li>Subtask 3
<ul>
<li>Subtask 4</li>
</ul>
</li>
</ul>
</li>
</ul>
我尝试了以下帖子并取得了一些成功:
Return unordered list from hierarchical sql data 和 C# Create HTML unordered list from List using Recursion
这是我从上面的第一个 link 改编而来的代码,它大部分都有效,但是如果更改了分层数据的顺序,该方法会在第一个不是 child 的前一个 parent。例如,如果我按如下方式更改数据列表的顺序,它将跳过子任务 1 和 2:
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
public class Task
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public Collection<Task> Tasks = new Collection<Task>( );
public Task FindTask( int id )
{
return FindTask( this, id );
}
private Task FindTask( Task task, int id )
{
if( task.Id == id )
{
return task;
}
Task returnTask = null;
foreach( Task child in task.Tasks )
{
returnTask = child.FindTask( id );
if( returnTask != null )
{
break;
}
}
return returnTask;
}
}
List<Task> topTasks = new List<Task>( );
protected void GetHierarchy( int id )
{
List<Task> data = new List<Task>( );
data.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
data.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
data.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
data.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
data.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
foreach( var row in data )
{
Task tasks = new Task( );
tasks.Title = row.Title;
tasks.Id = row.Id;
if( row.ParentId == null )
{
topTasks.Add( tasks );
}
else
{
int parentId = row.ParentId.Value;
foreach( Task topTask in topTasks )
{
Task parentTask = topTask.FindTask( parentId );
if( parentTask != null )
{
parentTask.Tasks.Add( tasks );
break;
}
}
}
}
}
protected string Render( )
{
var s = new StringBuilder( );
GetHierarchy( id );
s.Append( "<ul>" );
foreach( Task child in topTasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
return s.ToString( );
}
private void RenderTask( StringBuilder s, Task task )
{
s.Append( "<li>" );
s.Append( task.Title );
if( task.Tasks.Count > 0 )
{
s.Append( "<ul>" );
foreach( Task child in task.Tasks )
{
RenderTask( s, child );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}
我不想使用 jquery 树视图或任何其他组件,因为这需要一个独立的解决方案。
任何人都可以建议我更好的方法,或者至少帮助我修复我在上面实现的代码,以便数据的顺序不会破坏递归?
提前致谢。
在您的 GetHierarchy 函数中,您将按顺序循环访问列表中的每个任务。如果列表中的第一个任务的 parentId 为空,那么它将被添加到 topTasks 列表中。
但是,如果第一个任务有一个非空的 parentId,那么它将被添加到 topTasks 中的父任务。请注意,这里的父任务还不存在于 topTasks 列表中,因此不会插入该任务。
我会使用一个递归函数,它首先获取具有空父项的任务,然后使用该任务的 ID 递归调用该函数,直到它到达树的底部。
一个粗略的例子:
Task addSubLists (List<Task> data, Task parent) {
foreach(Task task in data) {
if (task.parentId.Value == parent.Id.Value) {
parent.Tasks.Add(addSubLists(data, task));
}
}
return parent;
}
您将顶级任务传递给函数,它会添加所有后代。
最后,我改编了C# Create HTML unordered list from List using Recursion的答案,效果很好。这是我使用的代码:
protected string WriteList( )
{
var s = new StringBuilder( );
List<Task> tasks = new List<Task>( );
tasks.Add( new Task { Id = 2, ParentId = 1, Title = "Subtask 1" } );
tasks.Add( new Task { Id = 1, ParentId = null, Title = "Top task" } );
tasks.Add( new Task { Id = 3, ParentId = 2, Title = "Subtask 2" } );
tasks.Add( new Task { Id = 4, ParentId = 1, Title = "Subtask 3" } );
tasks.Add( new Task { Id = 5, ParentId = 4, Title = "Subtask 4" } );
s.Append( "<ul>" );
foreach( var task in tasks )
{
if( task.ParentId == null )
{
WriteTaskList( tasks, task, s );
}
}
s.Append( "</ul>" );
return s.ToString( );
}
private static void WriteTaskList( List<Task> tasks, Task task, StringBuilder s )
{
s.Append( "<li>" + task.Title );
var subtasks = tasks.Where( p => p.ParentId == task.Id );
if( subtasks.Count( ) > 0 )
{
s.Append( "<ul>" );
foreach( Task p in subtasks )
{
if( tasks.Count( x => x.ParentId == p.Id ) > 0 )
WriteTaskList( tasks, p, s );
else
s.Append( string.Format( "<li>{0}</li>", p.Title ) );
}
s.Append( "</ul>" );
}
s.Append( "</li>" );
}