Consider the situation of a field in sitecore meant to allow selecting a state, and the data items in sitecore are organized by country.
In this situation, it is most convenient for the content author to be able to navigate through the items in a static tree structure (yes static – the drop tree makes it a little easy to just escape out and lose where you were at navigating!).
Which is why, we came up with the need for a treelist – which allows single item selection.
This can be achieved in 2 ways:
Add validation on the existing TreeList control:
This can be done using the validation field on the sitecore field in question. The following regular expression should help achieve this:
^$|^{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}$
Here’s how the validation message shows up – to note here – this validation message comes up only on item save, as opposed to while adding the multiple items in the field.
Create a new control and add validation / transform view:
If you did have additional requirements – say sorting the items in the treelist a certain custom way in addition to restricting the number of selections to 1, you could go all out and create a new control, inheriting from the existing treelist control.
I went in and grabbed the existing code of the treelist using a reflector, and updated the code as was needed.
Below are the updates that were made (the remaining code of Sitecore.Shell.Applications.ContentEditor.TreeList were left in as is)
namespace MySite.SitecoreFields { public class SingleSelectTree : TreeList { ... ... [Category("Data")] [Description("If set to Yes, allows only 1 item to be selected in the control")] public bool RestrictSingleSelection { get { return this.GetViewStateBool("RestrictSingleSelection"); } set { this.SetViewStateBool("RestrictSingleSelection", value); } } ... ... protected new void Add() { if (Disabled) return; string viewStateString = GetViewStateString("ID"); TreeviewEx treeviewEx = FindControl(viewStateString + "_all") as TreeviewEx; Assert.IsNotNull(treeviewEx, typeof(DataTreeview)); Listbox listbox = FindControl(viewStateString + "_selected") as Listbox; Assert.IsNotNull(listbox, typeof(Listbox)); if (treeviewEx != null) { Item selectionItem = treeviewEx.GetSelectionItem(Language.Parse(this.ItemLanguage), Sitecore.Data.Version.Latest); if (selectionItem == null) { SheerResponse.Alert("Select an item in the Content Tree.", new string[0]); } else { if (HasExcludeTemplateForSelection(selectionItem)) return; if (ItemSelected(selectionItem, listbox)) { SheerResponse.Alert("You cannot select more than one item.", new string[0]); } else if (IsDeniedMultipleSelection(selectionItem, listbox)) { SheerResponse.Alert("You cannot select the same item twice.", new string[0]); } else { if (!this.HasIncludeTemplateForSelection(selectionItem)) return; SheerResponse.Eval("scForm.browser.getControl('" + viewStateString + "_selected').selectedIndex=-1"); ListItem listItem = new ListItem { ID = GetUniqueID("L") }; Sitecore.Context.ClientPage.AddControl(listbox, listItem); listItem.Header = GetHeaderValue(selectionItem); listItem.Value = listItem.ID + (object)"|" + selectionItem.ID; SheerResponse.Refresh(listbox); TreeList.SetModified(); } } } } private bool ItemSelected(Item item, Listbox listbox) { Assert.ArgumentNotNull(listbox, "listbox"); if (item == null) return true; if (!RestrictSingleSelection) return false; return (from Control control in listbox.Controls select control.Value.Split('|')).Count() > 1; } ... ... private void SetProperties() { Guid tempGuid; string @string = StringUtil.GetString(new string[1] { this.Source }); if (@string.StartsWith("query:")) { if (Sitecore.Context.ContentDatabase == null || this.ItemID == null) return; Item current = Sitecore.Context.ContentDatabase.GetItem(this.ItemID); if (current == null) return; Item obj = null; try { obj = LookupSources.GetItems(current, @string).FirstOrDefault(); } catch (Exception ex) { Log.Error("Treelist field failed to execute query.", ex, (object)this); } if (obj == null) return; this.DataSource = obj.Paths.FullPath; } else if (Guid.TryParse(@string, out tempGuid)) this.DataSource = this.Source; else if (this.Source != null && !@string.Trim().StartsWith("/", StringComparison.OrdinalIgnoreCase)) { this.ExcludeTemplatesForSelection = StringUtil.ExtractParameter("ExcludeTemplatesForSelection", this.Source).Trim(); this.IncludeTemplatesForSelection = StringUtil.ExtractParameter("IncludeTemplatesForSelection", this.Source).Trim(); this.IncludeTemplatesForDisplay = StringUtil.ExtractParameter("IncludeTemplatesForDisplay", this.Source).Trim(); this.ExcludeTemplatesForDisplay = StringUtil.ExtractParameter("ExcludeTemplatesForDisplay", this.Source).Trim(); this.ExcludeItemsForDisplay = StringUtil.ExtractParameter("ExcludeItemsForDisplay", this.Source).Trim(); this.IncludeItemsForDisplay = StringUtil.ExtractParameter("IncludeItemsForDisplay", this.Source).Trim(); this.AllowMultipleSelection = string.Compare(StringUtil.ExtractParameter("AllowMultipleSelection", this.Source).Trim().ToLowerInvariant(), "yes", StringComparison.InvariantCultureIgnoreCase) == 0; this.RestrictSingleSelection = string.Compare(StringUtil.ExtractParameter("RestrictSingleSelection", this.Source).Trim().ToLowerInvariant(), "yes", StringComparison.InvariantCultureIgnoreCase) == 0; this.DataSource = StringUtil.ExtractParameter("DataSource", this.Source).Trim().ToLowerInvariant(); this.DatabaseName = StringUtil.ExtractParameter("databasename", this.Source).Trim().ToLowerInvariant(); } else this.DataSource = this.Source; } } }
Additionally you would need the corresponding sitecore updates in the Core database to add the new control:
You’d need the corresponding config updates here:
<sitecore> <!-- New control added - Single Select Tree --> <controlSources> <source mode="on" namespace="MySite.SitecoreFields" assembly="MySite" prefix="contentExtension" /> </controlSources> </sitecore>
And the control should now be available:
[…] the type of data this new custom field will contain. For example, the Single Select with Search, Single Select Tree fields are link fields and contain a single guid, while Multisite Multilist with Search is a […]
LikeLike