Dynamically registering custom trees without writing to UmbracoAppTree

When creating custom trees in Umbraco, the standard rule of thumb is that you need to register your tree definition into the UmbracoAppTree table so that it shows up in the back-office for a particular application. Well here’s a little secret gem that has been around since version 4 … you don’t actually need to register your trees in the database, you just need to register them in code (however, read the important note at the end of this post!)

In the Umbraco codebase there is a Singleton class called: TreeDefinitionCollection which contains the definitions of all of the trees that are registered in the UmbracoAppTree database table. It just so happens that the TreeDefinitionCollection is a mutable collection, meaning you can dynamically add/remove items from it at runtime. So, here’s how you do it:

Somewhere in your application, you’ll need to add a new tree definition to this collection and you’ll definitely want to do the registration before you want your tree to be rendered, so you’ve got a couple of options here:

  • Global.asax or module
  • In an ApplicationBase class of your own
  • Or, some class, static constructor, etc… that you know will be executed before your tree is rendered

You’ll also need to put a lock on your code, otherwise you might run into concurrency issues. This example registers my custom FilteredContentTree in a static constructor method for my data type. Since this data type is the only object that requires this tree, I know that this code is going to execute before the tree is ever rendered.

public MultiNodeTreePickerDataEditor() { //check if my custom tree is already registered if (TreeDefinitionCollection.Instance .Where(x => x.TreeType == typeof(FilteredContentTree)) .Count() == 0) { lock (m_Locker) { //double check lock.... if (TreeDefinitionCollection.Instance .Where(x => x.TreeType == typeof(FilteredContentTree)) .Count() == 0) { //need to add our tree definitions to the collection. //find the content tree to duplicate var contentTree = TreeDefinitionCollection.Instance .Where(x => x.Tree.Alias == "content").Single(); //create the tree definition with the same details //as the standard content tree, however mark it as 'initialize' = false //which means that it won't be rendered by default in the umbraco //back-office, only when I use the tree control to render it //directly for my data type. var filteredContentTree = new TreeDefinition(typeof(FilteredContentTree), new umbraco.BusinessLogic.ApplicationTree(true, false, 0, contentTree.Tree.ApplicationAlias, "FilteredContentTree", contentTree.Tree.Title, contentTree.Tree.IconClosed, contentTree.Tree.IconOpened, "uComponents.Core", "DataTypes.MultiNodeTreePicker.FilteredContentTree", contentTree.Tree.Action), contentTree.App); //add it to the collection at runtime TreeDefinitionCollection.Instance.Add(filteredContentTree); } } } }

I

think the code/comments are fairly straight forward. As you can see, registering a custom tree into the collection at runtime is very easy! No database work required :)

IMPORTANT NOTE: Though this is nice and easy to do, this does prevent your users from being able to remove trees that they don’t want!! They would only have 2 options at their disposal to remove the tree that they no longer want:

  • Delete the assembly that is registering the tree
  • OR, use their own code to unregister the tree

The example that I’ve used above is for the Multi-node tree picker in uComponents and is used for the data type only (which is why it is registered to not be initialized).

Enjoy!

Author

Administrator (1)

comments powered by Disqus