I'm trying to print a simple HTML tree structure, consisting of ul
and li
elements. 开发者_如何学GoI want to be able to pass the view an IEnumerable<T>
where T has some hiearchy information (e.g. parent). Now I want the view to output the Tree control much like ASP.NET's Tree used to work. Is there any way to do this in MVC3 using Razor?
I've so far ended up doing it like this:
@PrintCategoryTree(Model.Where(x => !x.ParentCategoryID.HasValue))
@functions{
public IHtmlString PrintCategoryTree(IEnumerable<Aurora.Models.Category> levelCategories) {
if (levelCategories.Count() == 0) { return new HtmlString(String.Empty); }
System.Text.StringBuilder sb = new System.Text.StringBuilder();
TagBuilder childBuilder = new TagBuilder("li");
foreach(var item in levelCategories.OrderBy(x => x.Name)) {
childBuilder.Attributes.Clear();
childBuilder.Attributes.Add("id", item.CategoryID.ToString("N"))
var sub = PrintCategoryTree(Model.Where(x => x.ParentCategoryID == item.CategoryID));
childBuilder.InnerHtml = item.Name + sub.ToString();
sb.AppendLine(childBuilder.ToString());
}
TagBuilder tagBuilder = new TagBuilder("ul")
{
InnerHtml = sb.ToString()
};
return Html.Raw(tagBuilder.ToString());
}
}
The reason being, this is still in the Razor View. And I can keep my presentation logic in my view. It's not exactly what I'd hoped, but I thought I'd share it with you guys here anyway.
Sure it's possible. :) You can acctually go about this in a few ways.
Use something like jsTree and only output the first level of the tree. When a user expands a node, jsTree issues an AJAX callback to get more, and that's just a matter of loading the nodes underneath whatever they opened. I know that's not exactly what you asked, but I wanted to mention it.
If you can either modify the query or do a bit of pre-processing on the data before passing it to razor, change each item in the IEnumberable so that it also includes it's "level" in the tree (1 for a root node, 2 for it's child, 3 for a child of a child, etc). Outputting it at that point is pretty easy. Create a variable in the view holding the current level. When you go to the next row, check if the new level is the same as the old one. If it's not, either open or close enough
<ul>
tags that you get to the right one for that element.If you can't do that either, you'll need to keep track of the nodes as you see them in razor. The reason why is that when you find a child from a node that isn't the last one you saw, you'll need to get that node back to figure out how many
</ul>
tags you need to add to get to the right level. Off the top of my head you could do that by having the view create a Hashtable with the row's key and level for each row you hit. Then when you hit an element and don't know where to put it, look up its parent in the hashtable (since you'll have already seen the parent assuming these are ordered correctly).
Far as I'm aware there's no "display this blob of stuff as a tree" command, so you need to write some logic to get the number of tags to build the levels correct. But hopefully that will help you get started. :)
精彩评论