TreeView Architecture

The TreeView architecture is very simple, because it delegates a lot of the work to the browser's DOM.

The control is 100% data-bound. The itemsSource property defines an array of data items that represent nodes and may contain child elements (as defined by the childItemsPath property). When one of the binding properties change, the control populates its DOM by scanning the itemsSource array and creating DOM elements to represent the nodes.

There is no virtualization, so the number of DOM elements remains constant as the user scrolls the control, collapses or expands nodes. This is not a significant limitation since the TreeView supports lazy-loading, which allows you to load data as the user requests it (by expanding the nodes).

The TreeView has a selectedItem property that gets or sets the data item in the itemsSource array that is currently selected. It also has a selectedNode property that gets or sets the tree node that wraps the current item. You can use the selectedNode property to collapse, expand, or move the selection. You use the TreeView's getNode method to get a reference to the node that represents a given data item.

To change the tree, you will normally change the itemsSource array and call the loadTree method to re-generate the nodes. The example below shows the performance of the TreeView when binding to sources of different sizes:



Node 1.1
Node 2.1
Node 2.2
Node 2.3
Node 2.4
Node 2.5
Node 2.1
Node 2.2
Node 2.3
Node 2.4
Node 2.5
Node 2.1
Node 2.2
Node 2.3
Node 2.4
Node 2.5
Node 2.1
Node 2.2
Node 2.3
Node 2.4
Node 2.5
Node 2.1
Node 2.2
Node 2.3
Node 2.4
Node 2.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// This file locates: "Scripts/Lesson/C1Nav/Architecture.js".
c1.documentReady(function () {
    var cmbLevels = wijmo.Control.getControl('#cmbLevels');
    var cmbNodesPerLevel = wijmo.Control.getControl('#cmbNodesPerLevel');
    var theTree = wijmo.Control.getControl('#theTree');
 
    theTree.itemsSource = getData();
    theTree.displayMemberPath = 'header';
    theTree.childItemsPath = 'items';
 
    // re-bind tree
    document.getElementById('bind').addEventListener('click', function (e) {
        var start = Date.now();
        theTree.itemsSource = getData();
        theTree.loadTree(); // force immediate refresh
        var msg = wijmo.format('Bound to <b>{cnt:no}</b> nodes in <b>{ms:n0}</b> ms.', {
            cnt: theTree.totalItemCount,
            ms: Date.now() - start
        });
        document.getElementById('bindingMsg').innerHTML = msg;
    });
    // get the data
    function getData() {
        var cnt = cmbNodesPerLevel.selectedValue,
                levels = cmbLevels.selectedValue;
        nodes = [];
        for (var i = 0; i < cnt; i++) {
            nodes.push(getNode(0, i, cnt, levels))
        }
        return nodes;
    }
    function getNode(level, id, cnt, levels) {
 
        // create node
        var node = {
            header: 'Node ' + (level + 1) + '.' + (id + 1),
        };
 
        // create child nodes
        if (level < levels - 1) {
            node.items = [];
            for (var i = 0; i < cnt; i++) {
                node.items.push(getNode(level + 1, i, cnt, levels))
            }
        }
 
        // done
        return node;
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// This file locates: "Content/css/Lesson/C1Nav/Architecture.css".
/* default trees on this sample */
.demo-control .wj-treeview {
    height: 350px;
    font-size: 120%;
    margin-top: 8px;
    margin-bottom: 8px;
    padding: 6px;
    background: #f0f0f0;
    box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
}
 
.wj-combobox {
  width: 120px;
}
 
label {
  width: 120px;
  text-align: right;
  margin-bottom: 12px;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
using System.Web.Mvc;
 
namespace LearnMvcClient.Controllers
{
    public partial class C1NavController : Controller
    {
        // GET: Architecture
        public ActionResult Architecture()
        {
            return View();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<h1>
    @Html.Raw(Resources.C1Nav.Architecture_Title)
</h1>
 
<p>
    @Html.Raw(Resources.C1Nav.Architecture_Text1)
</p>
<p>
    @Html.Raw(Resources.C1Nav.Architecture_Text2)
</p>
<p>
    @Html.Raw(Resources.C1Nav.Architecture_Text3)
</p>
<p>
    @Html.Raw(Resources.C1Nav.Architecture_Text4)
</p>
<p>
    @Html.Raw(Resources.C1Nav.Architecture_Text5)
</p>
 
<div class="row demo-settings">
    <div class="col-xs-6">
        <label for="cmbLevels">
            @Html.Raw(Resources.C1Nav.Architecture_Text6)
        </label>
        @(Html.C1().ComboBox<int>().Id("cmbLevels").Bind(new[] { 1, 2, 3 }).SelectedValue(2))
        <br />
        <label for="cmbLevels">
            @Html.Raw(Resources.C1Nav.Architecture_Text7)
        </label>
        @(Html.C1().ComboBox<int>().Id("cmbNodesPerLevel").Bind(new[] { 5, 10, 20, 40 }).SelectedValue(5))
        <br />
        <label></label>
        <button class="btn btn-primary" id="bind">
            @Html.Raw(Resources.C1Nav.Architecture_Text8)
        </button>
        <div id="bindingMsg"></div>
    </div>
    <div class="col-xs-6">
        @Html.C1().TreeView().Id("theTree")
    </div>
</div>