/// <summary> /// Gets the tree's current layout of expanded / selected /// nodes. /// </summary> /// <returns>The tree layout.</returns> public virtual TreeLayout GetTreeLayout() { TreeLayout layout = new TreeLayout(); T selected = SelectedItem; //set selected item if (selected != null) { layout.SelectedItemId = GetItemKey(selected); } //if there is no tree yet, we're done if (Tree != null) { //get nodes of all expanded nodes GetExpandedNodes(layout.ExpandedNodeIds, Tree.Items); } return(layout); }
/// <summary> /// Renders the tree and optionally preserves its current layout. /// </summary> /// <param name="items">The items to be displayed on the tree.</param> /// <param name="layout">The layout to be applied on the tree.</param> private void RenderTree(IEnumerable <T> items, TreeLayout layout) { //clear monitored items monitor.Clear(); //if there is no tree, there is nothing to render if (Tree == null) { return; } //set rendered flag isTreeRendered = true; //suppress selection change event if the tree is cleared ignoreItemChangeEvents = true; //clear all items (root, if available, will be re-added) Tree.Items.Clear(); TreeViewItem root = RootNode; if (root != null) { //if we have a root node, clear and expand it root.Items.Clear(); root.IsExpanded = true; Tree.Items.Add(root); } //if a null value was assigned (no items), we're done if (items == null) { return; } //recreate root item nodes (childs will be created automatically //according to the layout) List <TreeViewItem> rootList = new List <TreeViewItem>(); foreach (T item in items) { CreateItemNode(item, rootList, layout); } //assign all items at once to the tree //-> render within root, or on the tree itself ItemCollection treeNodes = root != null ? root.Items : Tree.Items; foreach (TreeViewItem item in rootList) { treeNodes.Add(item); } //verify the selected node - if it does no longer exist, reset //the SelectedItem property TreeViewItem selectedNode = null; if (layout != null) { string itemId = layout.SelectedItemId; selectedNode = TryFindItemNode(Tree.Items, itemId, true); } if (selectedNode == null) { SelectedItem = null; } if (Tree.IsKeyboardFocusWithin && selectedNode != null) { //if the tree has the focus, this will auto-select the root node once //the tree is rendered - prevent this by explicitely setting the focus //to root, than to the selected item //-> both select are needed, depending on the currently selected item //(direct child of root or not makes a difference) if (root != null) { Keyboard.Focus(root); } Keyboard.Focus(selectedNode); } //reactivate events ignoreItemChangeEvents = false; //store layout or create a new one currentLayout = layout ?? new TreeLayout(); }
/// <summary> /// Creates a single <see cref="TreeViewItem"/> node that represents a /// given item of the <see cref="Items"/> collection and assigns the /// item to the node's <see cref="HeaderedItemsControl.Header"/> /// property.<br/> /// If the node's child item collection should be observed for changes /// (<see cref="ObserveChildItemsProperty"/>), the item's child collection /// is registered with the tree's <see cref="ItemMonitor{T}"/>. /// </summary> /// <param name="item">The item which is being represented by a tree node.</param> /// <param name="parentNodes">The parent collection that contains the created /// tree node item.</param> /// <param name="layout">Stores a predefined layout for the tree. May be null.</param> protected internal void CreateItemNode(T item, IList parentNodes, TreeLayout layout) { bool hasLayout = layout != null; //create a tree node and assign the represented item to the //node header TreeViewItem treeNode = CreateTreeViewItem(item); treeNode.Header = item; ApplyNodeStyle(treeNode, item); //get the unique ID of the item and its child items string itemKey = GetItemKey(item); //check node state bool isExpanded = hasLayout && layout.IsNodeExpanded(itemKey); bool renderChilds = isExpanded || !IsLazyLoading; bool hasChilds; //only invoke GetChildItems directly if we *need* the //collection. This is the case if the node is expanded or //collection monitoring is active ICollection <T> childItems = null; if (renderChilds || ObserveChildItems) { childItems = GetChildItems(item); hasChilds = childItems.Count > 0; } else { //invoke the potentially cheaper operation hasChilds = HasChildItems(item); } if (renderChilds) { //render childs if the node is expanded according to the //layout information, or if lazy loading is not active foreach (T childItem in childItems) { CreateItemNode(childItem, treeNode.Items, layout); } if (isExpanded) { treeNode.IsExpanded = true; } } else if (hasChilds) { //if the item has child nodes which we don't need to create right //now (not expanded and lazy loading is active), insert //a dummy node which results in an expansion indicator treeNode.Items.Add(new TreeViewItem()); } if (hasLayout && itemKey.Equals(layout.SelectedItemId) || item == SelectedItem) { //select the item and notify treeNode.IsSelected = true; } //finally, if we should monitor the child collection, register it if (ObserveChildItems) { monitor.RegisterItem(itemKey, childItems); } //sort node contents ApplySorting(treeNode, item); //add node to the parent's items collection parentNodes.Add(treeNode); }
/// <summary> /// Recreates the tree with a given tree layout. /// </summary> /// <param name="layout">Defines the layout of the tree.</param> public virtual void Refresh(TreeLayout layout) { RenderTree(Items, layout); }