# FTRTreeList

## Overview

`FTRTreeList` is a Windows Forms tree/list control provided by **FTR Controls**.

It is designed for displaying hierarchical data in multiple columns and supports:

* Hierarchical parent/child nodes
* Multiple columns
* Expand/collapse
* Node selection
* Optional three-state checkboxes
* Node icons
* Text filtering
* Loading hierarchical data from a `DataTable`
* Keyboard navigation
* Mouse interaction
* RTL layouts
* Light, Dark, Duotone, and Color themes
* Optional Premium features

The control is intended to be used as a standard Windows Forms control and can be added to a form either from the Visual Studio Toolbox or programmatically.

---

## Namespace and Type

**Namespace**

```csharp
FTRControls
```

**Control**

```csharp
FTRTreeList
```

**Base class**

```csharp
FTRControls.BaseClasses.FTRBaseUserControl
```

The control is available in the Visual Studio Toolbox under the **FTR Controls** category.

---

# Getting Started

## Adding FTRTreeList to a Form

The control can be added from the Visual Studio Toolbox or created programmatically.

Example:

```csharp
var tree = new FTRTreeList
{
    Dock = DockStyle.Fill
};

Controls.Add(tree);
```

You can then define the columns and nodes.

---

# Columns

Columns are defined using `FTRTreeColumn`.

## Creating a Column

`FTRTreeColumn` has the following constructor:

```csharp
public FTRTreeColumn(string text, int width)
```

Example:

```csharp
tree.Columns.Add(new FTRTreeColumn("Name", 250));
tree.Columns.Add(new FTRTreeColumn("Size", 100));
tree.Columns.Add(new FTRTreeColumn("Type", 120));
```

### Column properties

| Property     | Type     | Description                         |
| ------------ | -------- | ----------------------------------- |
| `HeaderText` | `string` | Text displayed in the column header |
| `Width`      | `int`    | Width of the column in pixels       |

Example:

```csharp
var column = new FTRTreeColumn("Name", 250);

tree.Columns.Add(column);
```

---

# Important: Column and Cell Mapping

The first column is the tree column.

Its displayed text comes from:

```csharp
FTRTreeNode.Text
```

Additional columns use the values stored in:

```csharp
FTRTreeNode.Cells
```

For example, if the control has three columns:

```text
Column 0: Name
Column 1: Size
Column 2: Type
```

the node should provide:

```csharp
var node = new FTRTreeNode(
    "Report.pdf",
    "125 KB",
    "PDF"
);
```

The mapping is:

```text
Column 0 -> node.Text
Column 1 -> node.Cells[0]
Column 2 -> node.Cells[1]
```

Therefore, when using multiple columns, make sure that the number and order of values supplied to the node match the additional columns.

---

# Creating Nodes

Hierarchical data is represented by `FTRTreeNode`.

## Creating a Node

The constructor is:

```csharp
public FTRTreeNode(string text, params object[] cells)
```

Example:

```csharp
var document = new FTRTreeNode(
    "Report.pdf",
    "125 KB",
    "PDF"
);
```

The first argument is displayed as the tree text.

Additional arguments are stored in `Cells`.

---

# Building a Tree Manually

A tree can be created by adding root nodes and child nodes.

Example:

```csharp
var tree = new FTRTreeList
{
    Dock = DockStyle.Fill
};

tree.Columns.Add(new FTRTreeColumn("Name", 250));
tree.Columns.Add(new FTRTreeColumn("Type", 120));

var documents = new FTRTreeNode("Documents");

var reports = new FTRTreeNode("Reports");

var report = new FTRTreeNode(
    "Report.pdf",
    "PDF"
);

reports.AddNode(report);
documents.AddNode(reports);

tree.Nodes.Add(documents);

Controls.Add(tree);
```

The resulting hierarchy is:

```text
Documents
└── Reports
    └── Report.pdf
```

---

# Adding Nodes

The control provides:

```csharp
AddNode(FTRTreeNode parent, FTRTreeNode child)
```

If `parent` is `null`, the node is added as a root node.

## Add a Root Node

```csharp
tree.AddNode(null, new FTRTreeNode("Documents"));
```

## Add a Child Node

```csharp
var documents = new FTRTreeNode("Documents");

tree.AddNode(null, documents);

var report = new FTRTreeNode("Report.pdf");

tree.AddNode(documents, report);
```

`AddNode` automatically updates the node hierarchy and refreshes the control.

---

# FTRTreeNode Properties

The following public properties are available on `FTRTreeNode`.

| Property     | Type                | Description                                        |
| ------------ | ------------------- | -------------------------------------------------- |
| `Text`       | `string`            | Main text displayed in the tree column             |
| `Cells`      | `object[]`          | Values displayed in columns after the first column |
| `Nodes`      | `List<FTRTreeNode>` | Child nodes                                        |
| `Parent`     | `FTRTreeNode`       | Parent node                                        |
| `IsExpanded` | `bool`              | Indicates whether child nodes are expanded         |
| `Level`      | `int`               | Current hierarchy level                            |
| `CheckState` | `CheckState`        | Current checkbox state                             |
| `Tag`        | `object`            | Application-defined data associated with the node  |
| `Icon`       | `Image`             | Optional icon displayed next to the node text      |
| `IsVisible`  | `bool`              | Controls whether the node is visible               |
| `IsMatch`    | `bool`              | Indicates that the node matches the current filter |

`Level`, `IsVisible`, and `IsMatch` are managed by the control and normally do not need to be changed by the application.

---

# Using Tag

`Tag` can be used to associate application-specific information with a node.

Example:

```csharp
var customer = new Customer
{
    Id = 1001,
    Name = "Contoso"
};

var node = new FTRTreeNode(customer.Name)
{
    Tag = customer
};
```

Later, the application can retrieve the original object:

```csharp
var customer = (Customer)node.Tag;
```

When data is loaded using `LoadFromDataTable`, the corresponding `DataRow` is automatically assigned to the node's `Tag` property.

---

# Using Icons

A node can display an optional `Image`.

Example:

```csharp
var node = new FTRTreeNode("Documents")
{
    Icon = Properties.Resources.FolderIcon
};
```

The icon is displayed in the first/tree column.

---

# Expanding and Collapsing

Each node has an `IsExpanded` property.

```csharp
node.IsExpanded = true;
```

or:

```csharp
node.IsExpanded = false;
```

The control also provides methods for changing the entire tree state.

## Expand All

```csharp
tree.ExpandAll();
```

## Collapse All

```csharp
tree.CollapseAll();
```

These operations apply recursively to the entire node hierarchy.

---

# BeforeExpand Event

The `BeforeExpand` event is raised immediately before a collapsed node is expanded.

The event is cancelable.

Example:

```csharp
tree.BeforeExpand += (sender, e) =>
{
    if (e.Node.Tag == null)
    {
        e.Cancel = true;
    }
};
```

If:

```csharp
e.Cancel = true;
```

the node will not be expanded.

This event is raised when expanding a node. It is not raised when collapsing a node.

---

# Selecting Nodes

The currently selected node is available through:

```csharp
tree.SelectedNode
```

Example:

```csharp
FTRTreeNode selected = tree.SelectedNode;
```

A node can also be selected programmatically:

```csharp
tree.SelectedNode = node;
```

When a node is selected, the `NodeSelected` event is raised.

Example:

```csharp
tree.NodeSelected += (sender, e) =>
{
    var node = e.Node;

    statusLabel.Text = node.Text;
};
```

---

# NodeSelected Event

`NodeSelected` is raised when the current selection changes.

Event argument:

```csharp
FTRNodeEventArgs
```

The selected node is available through:

```csharp
e.Node
```

Example:

```csharp
tree.NodeSelected += OnNodeSelected;

private void OnNodeSelected(
    object sender,
    FTRNodeEventArgs e)
{
    MessageBox.Show($"Selected: {e.Node.Text}");
}
```

---

# Checkboxes

Three-state checkboxes are an optional Premium feature.

Enable them with:

```csharp
tree.ShowCheckBoxes = true;
```

When enabled, the checkbox is displayed in the tree column.

It is **not a separate checkbox column**.

## License Requirement

`ShowCheckBoxes` is a Premium feature.

If the control is not activated with a valid FTR Controls license, attempting to enable this property will trigger the license activation prompt and the requested value will not be applied.

---

# Check States

Each node has a `CheckState` property:

```csharp
System.Windows.Forms.CheckState
```

The possible states are:

```csharp
CheckState.Unchecked
CheckState.Checked
CheckState.Indeterminate
```

Example:

```csharp
node.CheckState = CheckState.Checked;
```

---

# Checkbox Behavior

When a user checks or unchecks a node:

1. The node changes between `Checked` and `Unchecked`.
2. The same state is applied recursively to all child nodes.
3. Parent nodes are recalculated.
4. A parent can become `Indeterminate` when its children have mixed states.
5. `NodeCheckStateChanged` is raised for the node that was toggled.

For example:

```text
Documents       Indeterminate
├── Report      Checked
├── Invoice     Unchecked
└── Contract    Checked
```

The parent is `Indeterminate` because its children do not all have the same state.

---

# NodeCheckStateChanged Event

Use this event to respond to checkbox changes.

Example:

```csharp
tree.NodeCheckStateChanged += (sender, e) =>
{
    var node = e.Node;

    Console.WriteLine(
        $"{node.Text}: {node.CheckState}");
};
```

The event argument is:

```csharp
FTRNodeEventArgs
```

---

# Getting Checked Nodes

Use:

```csharp
List<FTRTreeNode> checkedNodes = tree.GetCheckedNodes();
```

The returned list contains nodes whose state is not `Unchecked`.

Therefore, nodes with either of these states are included:

```csharp
CheckState.Checked
CheckState.Indeterminate
```

Example:

```csharp
var selectedItems = tree.GetCheckedNodes();

foreach (var node in selectedItems)
{
    Console.WriteLine(node.Text);
}
```

---

# Filtering

The control supports text filtering through:

```csharp
tree.Filter(keyword);
```

Example:

```csharp
tree.Filter("report");
```

Filtering is case-insensitive.

The filter checks the node's:

```csharp
Text
```

property.

It does not search the values stored in `Cells` or `Tag`.

---

# Filter Behavior

When a node matches the search text:

```text
IsMatch = true
```

The node remains visible.

If a child node matches, its parent nodes are also made visible so that the matching node can be reached through the hierarchy.

Matching descendants also cause the required parent nodes to be expanded.

For example, filtering for:

```text
Report
```

can produce:

```text
Documents
└── Reports
    └── Report.pdf   <-- match
```

even if `Documents` and `Reports` themselves do not contain the search term.

---

# Clearing the Filter

Pass an empty or whitespace-only string:

```csharp
tree.Filter("");
```

or:

```csharp
tree.Filter(null);
```

This clears the filter and makes the nodes visible again.

---

# Filter License Requirement

Filtering with a non-empty keyword is a Premium feature.

If the control is not licensed, a non-empty filter request is ignored.

Clearing the filter with an empty or whitespace-only value does not require the Premium feature.

---

# Loading Data from a DataTable

The control can build a hierarchical tree directly from a `DataTable`.

Method:

```csharp
LoadFromDataTable(
    DataTable dt,
    string idColumn,
    string parentIdColumn,
    string textColumn,
    string[] extraCellColumns = null
)
```

This is a Premium feature.

---

# DataTable Requirements

The source `DataTable` should contain:

* A unique identifier column
* A parent identifier column
* A text/display column
* Optional additional columns

For example:

| Id | ParentId | Name       | Type   | Size   |
| -- | -------- | ---------- | ------ | ------ |
| 1  | NULL     | Documents  | Folder | NULL   |
| 2  | 1        | Reports    | Folder | NULL   |
| 3  | 2        | Report.pdf | File   | 125 KB |
| 4  | 1        | Images     | Folder | NULL   |

The relationship is established using:

```text
Id
ParentId
```

A row is considered a root node when its parent ID is empty/NULL or when the specified parent ID does not exist in the table.

---

# Loading a DataTable

Example:

```csharp
tree.Columns.Add(new FTRTreeColumn("Name", 250));
tree.Columns.Add(new FTRTreeColumn("Type", 120));
tree.Columns.Add(new FTRTreeColumn("Size", 100));

tree.LoadFromDataTable(
    dataTable,
    "Id",
    "ParentId",
    "Name",
    new[]
    {
        "Type",
        "Size"
    }
);
```

The mapping is:

```text
Name -> FTRTreeNode.Text
Type -> FTRTreeNode.Cells[0]
Size -> FTRTreeNode.Cells[1]
```

The original `DataRow` is also stored in:

```csharp
FTRTreeNode.Tag
```

Example:

```csharp
tree.NodeSelected += (sender, e) =>
{
    DataRow row = e.Node.Tag as DataRow;

    if (row != null)
    {
        Console.WriteLine(row["Name"]);
    }
};
```

---

# Important DataTable Behavior

Calling `LoadFromDataTable` clears the existing root nodes before creating the new hierarchy.

Therefore, previously loaded nodes are replaced.

The control then automatically updates its layout.

---

# Premium Features

The following features require a valid FTR Controls license:

| Feature                  | API                      |
| ------------------------ | ------------------------ |
| Custom tree indentation  | `IndentWidth`            |
| Checkboxes               | `ShowCheckBoxes`         |
| DataTable loading        | `LoadFromDataTable(...)` |
| Non-empty text filtering | `Filter(keyword)`        |

If a Premium feature is used without a valid license, the control may display the license activation prompt or ignore the requested operation depending on the feature.

---

# Indentation

The indentation applied to each tree level is controlled by:

```csharp
tree.IndentWidth
```

Default value:

```text
20 pixels
```

Example:

```csharp
tree.IndentWidth = 30;
```

This is a Premium feature.

The indentation is calculated according to the node hierarchy level.

---

# Appearance

The control provides:

```csharp
HeaderHeight
RowHeight
```

Default values:

```text
HeaderHeight = 35
RowHeight    = 30
```

Example:

```csharp
tree.HeaderHeight = 40;
tree.RowHeight = 32;
```

These properties control the header and row dimensions.

---

# Themes

The control integrates with the FTR Controls theme system.

`ApplyTheme()` applies the currently active global FTR Controls theme to the tree.

Supported theme modes in the control include:

* Light
* Dark
* Duotone
* Color

Applications normally do not need to call `ApplyTheme()` manually when the global FTR Controls theme is managed by the application.

---

# Horizontal and Vertical Scrolling

The control automatically manages:

* Vertical scrolling when the number of visible rows exceeds the available height
* Horizontal scrolling when the total column width exceeds the available width

The scrollbars are displayed automatically when required.

---

# Right-to-Left Support

The control supports RTL layouts through the standard Windows Forms property:

```csharp
tree.RightToLeft = RightToLeft.Yes;
```

Example:

```csharp
tree.RightToLeft = RightToLeft.Yes;
```

The tree rendering, column positioning, text alignment, chevrons, and keyboard navigation adapt to RTL mode.

---

# Mouse Interaction

Users can interact with the tree using the mouse.

### Selecting a node

Clicking a row selects the node.

### Expanding/collapsing

Clicking the node's chevron expands or collapses it.

### Checking

When `ShowCheckBoxes` is enabled, clicking the checkbox changes the node's check state.

---

# Keyboard Navigation

The control supports keyboard navigation when it has focus.

## Up / Down

```text
Up
Down
```

Move the selection to the previous or next visible node.

## Right / Left

The behavior depends on the current RTL setting.

In LTR mode:

* `Right` expands the selected node.
* If already expanded, `Right` moves to the first visible child.
* `Left` collapses the selected node.
* If already collapsed, `Left` moves to the parent.

In RTL mode, the Left/Right behavior is mirrored.

## Space

When checkboxes are enabled:

```text
Space
```

toggles the selected node's checkbox state.

---

# Removing Nodes

Use:

```csharp
tree.RemoveNode(node);
```

This removes the specified node and its entire subtree.

Example:

```csharp
tree.RemoveNode(reportNode);
```

If the removed node is currently selected, the selection is cleared.

If a child node is removed while checkboxes are enabled, the parent check state is recalculated.

---

# Refreshing the Tree

Use:

```csharp
tree.UpdateTree();
```

This recalculates the visible hierarchy, node levels, scrollbars, and layout.

Call this method when application code changes the tree structure or node state directly and the visual layout needs to be refreshed.

---

# Complete Manual Example

The following example demonstrates a typical customer application scenario:

```csharp
using System;
using System.Drawing;
using System.Windows.Forms;
using FTRControls;

public class ExampleForm : Form
{
    private readonly FTRTreeList tree;
    private readonly Label statusLabel;

    public ExampleForm()
    {
        tree = new FTRTreeList
        {
            Dock = DockStyle.Fill,
            RowHeight = 30,
            HeaderHeight = 35
        };

        statusLabel = new Label
        {
            Dock = DockStyle.Bottom,
            Height = 25
        };

        tree.Columns.Add(
            new FTRTreeColumn("Name", 250));

        tree.Columns.Add(
            new FTRTreeColumn("Type", 120));

        tree.Columns.Add(
            new FTRTreeColumn("Size", 100));

        var documents = new FTRTreeNode("Documents");

        var reports = new FTRTreeNode("Reports");

        var report = new FTRTreeNode(
            "Report.pdf",
            "PDF",
            "125 KB");

        var invoice = new FTRTreeNode(
            "Invoice.pdf",
            "PDF",
            "80 KB");

        reports.AddNode(report);
        reports.AddNode(invoice);

        documents.AddNode(reports);

        tree.Nodes.Add(documents);

        tree.NodeSelected += Tree_NodeSelected;

        Controls.Add(tree);
        Controls.Add(statusLabel);
    }

    private void Tree_NodeSelected(
        object sender,
        FTRNodeEventArgs e)
    {
        statusLabel.Text =
            $"Selected: {e.Node.Text}";
    }
}
```

---

# Complete Checkbox Example

Checkboxes are a Premium feature.

```csharp
var tree = new FTRTreeList
{
    Dock = DockStyle.Fill,
    ShowCheckBoxes = true
};

tree.Columns.Add(
    new FTRTreeColumn("Name", 250));

var root = new FTRTreeNode("Documents");

root.AddNode(
    new FTRTreeNode("Report.pdf"));

root.AddNode(
    new FTRTreeNode("Invoice.pdf"));

tree.Nodes.Add(root);

tree.NodeCheckStateChanged += (sender, e) =>
{
    Console.WriteLine(
        $"{e.Node.Text}: {e.Node.CheckState}");
};

var checkedNodes = tree.GetCheckedNodes();
```

---

# Complete Filtering Example

Filtering is a Premium feature when a non-empty keyword is supplied.

```csharp
private void SearchTextBox_TextChanged(
    object sender,
    EventArgs e)
{
    tree.Filter(searchTextBox.Text);
}
```

To clear the filter:

```csharp
tree.Filter("");
```

The filter searches node text only.

---

# Complete DataTable Example

```csharp
var tree = new FTRTreeList
{
    Dock = DockStyle.Fill
};

tree.Columns.Add(
    new FTRTreeColumn("Name", 250));

tree.Columns.Add(
    new FTRTreeColumn("Type", 120));

tree.Columns.Add(
    new FTRTreeColumn("Size", 100));

tree.LoadFromDataTable(
    dataTable,
    "Id",
    "ParentId",
    "Name",
    new[]
    {
        "Type",
        "Size"
    });
```

For each resulting node:

```text
Text      = Name
Cells[0]  = Type
Cells[1]  = Size
Tag       = original DataRow
```

---

# Events Reference

| Event                   | Description                                                           |
| ----------------------- | --------------------------------------------------------------------- |
| `NodeSelected`          | Raised when a node is selected                                        |
| `NodeCheckStateChanged` | Raised when a node's checkbox state is toggled                        |
| `BeforeExpand`          | Raised before a collapsed node is expanded; expansion can be canceled |

---

# Event Argument Types

## FTRNodeEventArgs

Used by:

```text
NodeSelected
NodeCheckStateChanged
```

Property:

```csharp
FTRTreeNode Node
```

Example:

```csharp
private void OnNodeSelected(
    object sender,
    FTRNodeEventArgs e)
{
    var node = e.Node;
}
```

## FTRNodeCancelEventArgs

Used by:

```text
BeforeExpand
```

It provides:

```csharp
FTRTreeNode Node
```

and inherits from:

```csharp
CancelEventArgs
```

Therefore:

```csharp
e.Cancel = true;
```

prevents the expansion.

---

# API Reference

## FTRTreeList Properties

| Property         | Type                  | Default | Premium | Description                      |
| ---------------- | --------------------- | ------: | ------- | -------------------------------- |
| `Columns`        | `List<FTRTreeColumn>` |   Empty | No      | Columns displayed by the control |
| `Nodes`          | `List<FTRTreeNode>`   |   Empty | No      | Root nodes                       |
| `SelectedNode`   | `FTRTreeNode`         |  `null` | No      | Currently selected node          |
| `HeaderHeight`   | `int`                 |    `35` | No      | Header height in pixels          |
| `RowHeight`      | `int`                 |    `30` | No      | Row height in pixels             |
| `IndentWidth`    | `int`                 |    `20` | Yes     | Indentation per hierarchy level  |
| `ShowCheckBoxes` | `bool`                | `false` | Yes     | Enables three-state checkboxes   |

---

## FTRTreeList Methods

| Method                   | Description                            | Premium                        |
| ------------------------ | -------------------------------------- | ------------------------------ |
| `ApplyTheme()`           | Applies the current FTR Controls theme | No                             |
| `AddNode(parent, child)` | Adds a root or child node              | No                             |
| `RemoveNode(node)`       | Removes a node and its subtree         | No                             |
| `ExpandAll()`            | Expands all nodes                      | No                             |
| `CollapseAll()`          | Collapses all nodes                    | No                             |
| `Filter(keyword)`        | Filters nodes by `Text`                | Yes, when keyword is non-empty |
| `GetCheckedNodes()`      | Returns nodes that are not `Unchecked` | No                             |
| `LoadFromDataTable(...)` | Builds a hierarchy from a `DataTable`  | Yes                            |
| `UpdateTree()`           | Refreshes the tree layout              | No                             |

---

# FTRTreeColumn

```csharp
public FTRTreeColumn(string text, int width)
```

Properties:

| Property     | Type     | Description        |
| ------------ | -------- | ------------------ |
| `HeaderText` | `string` | Column header text |
| `Width`      | `int`    | Column width       |

---

# FTRTreeNode

```csharp
public FTRTreeNode(
    string text,
    params object[] cells)
```

Properties:

| Property     | Type                | Description                |
| ------------ | ------------------- | -------------------------- |
| `Text`       | `string`            | Tree column text           |
| `Cells`      | `object[]`          | Additional column values   |
| `Nodes`      | `List<FTRTreeNode>` | Child nodes                |
| `Parent`     | `FTRTreeNode`       | Parent node                |
| `IsExpanded` | `bool`              | Expansion state            |
| `Level`      | `int`               | Hierarchy level            |
| `CheckState` | `CheckState`        | Checkbox state             |
| `Tag`        | `object`            | Application-specific data  |
| `Icon`       | `Image`             | Optional node icon         |
| `IsVisible`  | `bool`              | Current visibility         |
| `IsMatch`    | `bool`              | Current filter match state |

Method:

```csharp
AddNode(FTRTreeNode node)
```

Adds a child node to the current node.

---

# Licensing Summary

| Capability                    | Standard | Premium |
| ----------------------------- | :------: | :-----: |
| Basic tree/list display       |     ✓    |         |
| Multiple columns              |     ✓    |         |
| Manual node creation          |     ✓    |         |
| Node selection                |     ✓    |         |
| Expand/collapse               |     ✓    |         |
| Icons                         |     ✓    |         |
| Themes                        |     ✓    |         |
| Horizontal/vertical scrolling |     ✓    |         |
| Keyboard navigation           |     ✓    |         |
| Custom `IndentWidth`          |          |    ✓    |
| `ShowCheckBoxes`              |          |    ✓    |
| Non-empty `Filter()`          |          |    ✓    |
| `LoadFromDataTable()`         |          |    ✓    |

A valid FTR Controls license is required for Premium functionality.

---

# Recommended Usage Pattern

For most applications, the recommended workflow is:

1. Create the `FTRTreeList`.
2. Define the columns.
3. Load or create the nodes.
4. Optionally enable Premium features.
5. Subscribe to the required events.
6. Add the control to the Windows Forms container.

For manually constructed data:

```text
Create FTRTreeList
        ↓
Create columns
        ↓
Create FTRTreeNode objects
        ↓
Build parent/child hierarchy
        ↓
Add root nodes
        ↓
Subscribe to events
        ↓
Use the control
```

For database/DataTable data:

```text
Create FTRTreeList
        ↓
Create columns
        ↓
Prepare DataTable
        ↓
Call LoadFromDataTable()
        ↓
Subscribe to events
        ↓
Use the control
```

---

# Customer Notes

* The first column displays `FTRTreeNode.Text`.
* Additional columns display values from `FTRTreeNode.Cells`.
* `Cells[0]` corresponds to the second configured column.
* Filtering searches `Text` only.
* `Tag` can be used to associate application-specific objects with nodes.
* `LoadFromDataTable()` automatically stores the source `DataRow` in `Tag`.
* `ShowCheckBoxes` enables three-state checkboxes inside the tree column; it does not create a separate checkbox column.
* `GetCheckedNodes()` returns both `Checked` and `Indeterminate` nodes.
* Premium features require an active FTR Controls license.
* `BeforeExpand` can prevent a node from being expanded.
* `UpdateTree()` can be used when the application changes the tree structure directly and needs to refresh the visual layout.
