/// <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>
        /// 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);
 }
        /// <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();
        }
 public override void Refresh(TreeLayout layout)
 {
     base.Refresh(layout);
     CountNodesAndCollections();
 }