Displaying the content tree programmatically
In this short technical article, I will show you some code that you can use to print out the content tree in its hierarchical order using our API. This code is only an example and has not been fully tested by Kentico. Please adjust the code as needed and only use it after testing in a secure environment.
In your custom code, you may want to display the Kentico content tree (or part of it). In the Portal Engine, this is easy to accomplish using web parts like the Universal Viewer, and in custom web parts you can use the BasicUniView control. But how do you do it with just C#?
To display hierarchical data, Kentico web parts and API use a GroupedDataSource, which you can read more about in our documentation. First, we will get the documents from the current site and create a GroupedDataSource:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var ds = DocumentHelper.GetDocuments()
.OnCurrentSite()
.Columns("NodeLevel", "NodeOrder", "NodeName", "NodeParentID", "NodeAliasPath", "DocumentName", "NodeID")
.OrderBy("NodeLevel, NodeOrder, NodeName")
.Result;
GroupedDataSource gpd = new GroupedDataSource(ds, "NodeParentID", "NodeLevel");
}
The OrderBy() method ensures that the results will appear in the same order as the content tree. The Columns() method limits the amount of data returned from the database for performance. If you want to use additional columns when displaying the page information, you need to add the column to the Columns() method.
We’ll use a StringBuilder to aggregate the listing when we loop through the items. For now, add an ASP:Literal to your page/control to display the content tree, and setup the StringBuilder:
protected override void OnLoad(EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.Append("<ul>");
var ds = DocumentHelper.GetDocuments()
.OnCurrentSite()
.Columns("NodeLevel", "NodeOrder", "NodeName", "NodeParentID", "NodeAliasPath", "DocumentName", "NodeID")
.OrderBy("NodeLevel, NodeOrder, NodeName")
.Result;
GroupedDataSource gpd = new GroupedDataSource(ds, "NodeParentID", "NodeLevel");
// TODO: Loop through data source and print items
sb.Append("</ul>");
ltlText.Text = sb.ToString();
}
A GroupedDataSource organizes objects into groups based on a parent-child relationship. To get the first level of our content tree, we can use GetGroupView(1) which represents all pages under the root node. We can then loop through the returned pages and print out their links, while checking for child pages and recursively printing those as well.
Here is our recursive method for printing a page link and the children of that page:
private void GetDataRowOutput(DataRowView drv, StringBuilder sb, GroupedDataSource gpd)
{
sb.Append("<li><a href=\"")
.Append(URLHelper.GetAbsoluteUrl(DocumentURLProvider.GetUrl(drv["NodeAliasPath"].ToString())))
.Append("\" title=\"")
.Append(drv["DocumentName"])
.Append("\">")
.Append(drv["DocumentName"])
.Append("</a>")
.Append("</li>");
int nodeID = Convert.ToInt32(drv["NodeID"]);
var items = gpd.GetGroupView(nodeID);
if (items != null)
{
sb.Append("<ul>");
foreach(var i in items) GetDataRowOutput(i, sb, gpd);
sb.Append("</ul>");
}
}
We can now include this method in our original code:
protected override void OnLoad(EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.Append("<ul>");
var ds = DocumentHelper.GetDocuments()
.OnCurrentSite()
.Columns("NodeLevel", "NodeOrder", "NodeName", "NodeParentID", "NodeAliasPath", "DocumentName", "NodeID")
.OrderBy("NodeLevel, NodeOrder, NodeName")
.Result;
GroupedDataSource gpd = new GroupedDataSource(ds, "NodeParentID", "NodeLevel");
var items = gpd.GetGroupView(0);
foreach (DataRowView drv in items)
{
GetDataRowOutput(drv, sb, gpd);
}
sb.Append("</ul>");
ltlText.Text = sb.ToString();
}
And the result is:
You can use this logic to print out any page information you need, not just links to the pages! As an example, this type of functionality may be useful as a custom macro or transformation method.